1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_cppu.hxx"
30 #include "jobqueue.hxx"
31 #include "threadpool.hxx"
32 
33 #include <osl/diagnose.h>
34 
35 using namespace ::osl;
36 
37 namespace cppu_threadpool {
38 
39 	JobQueue::JobQueue() :
40 		m_nToDo( 0 ),
41 		m_bSuspended( sal_False ),
42 		m_cndWait( osl_createCondition() )
43 	{
44 		osl_resetCondition( m_cndWait );
45 		m_DisposedCallerAdmin = DisposedCallerAdmin::getInstance();
46 	}
47 
48 	JobQueue::~JobQueue()
49 	{
50 		osl_destroyCondition( m_cndWait );
51 	}
52 
53 
54 	void JobQueue::add( void *pThreadSpecificData, RequestFun * doRequest )
55 	{
56 		MutexGuard guard( m_mutex );
57 		Job job = { pThreadSpecificData , doRequest };
58 		m_lstJob.push_back( job );
59 		if( ! m_bSuspended )
60 		{
61 			osl_setCondition( m_cndWait );
62 		}
63 		m_nToDo ++;
64 	}
65 
66 	void *JobQueue::enter( sal_Int64 nDisposeId , sal_Bool bReturnWhenNoJob )
67 	{
68 		void *pReturn = 0;
69 		{
70 			// synchronize with the dispose calls
71 			MutexGuard guard( m_mutex );
72 			if( m_DisposedCallerAdmin->isDisposed( nDisposeId ) )
73 			{
74 				return 0;
75 			}
76 			m_lstCallstack.push_front( nDisposeId );
77 		}
78 
79 
80 		while( sal_True )
81 		{
82 			if( bReturnWhenNoJob )
83 			{
84 				MutexGuard guard( m_mutex );
85 				if( m_lstJob.empty() )
86 				{
87 					break;
88 				}
89 			}
90 
91 			osl_waitCondition( m_cndWait , 0 );
92 
93 			struct Job job={0,0};
94 			{
95 				// synchronize with add and dispose calls
96 				MutexGuard guard( m_mutex );
97 
98 				if( 0 == m_lstCallstack.front() )
99 				{
100 					// disposed !
101                     if( m_lstJob.empty() )
102                     {
103                         osl_resetCondition( m_cndWait );
104                     }
105 					break;
106 				}
107 
108 				OSL_ASSERT( ! m_lstJob.empty() );
109 				if( ! m_lstJob.empty() )
110 				{
111 					job = m_lstJob.front();
112 					m_lstJob.pop_front();
113 				}
114 				if( m_lstJob.empty() )
115 				{
116 					osl_resetCondition( m_cndWait );
117 				}
118 			}
119 
120 			if( job.doRequest )
121 			{
122 				job.doRequest( job.pThreadSpecificData );
123 				m_nToDo --;
124 			}
125 			else
126 			{
127 				m_nToDo --;
128 				pReturn = job.pThreadSpecificData;
129 				break;
130 			}
131 		}
132 
133 		{
134 			// synchronize with the dispose calls
135 			MutexGuard guard( m_mutex );
136 			m_lstCallstack.pop_front();
137 		}
138 
139 		return pReturn;
140 	}
141 
142 	void JobQueue::dispose( sal_Int64 nDisposeId )
143 	{
144 		MutexGuard guard( m_mutex );
145 		for( CallStackList::iterator ii = m_lstCallstack.begin() ;
146 			 ii != m_lstCallstack.end() ;
147 			 ++ii )
148 		{
149 			if( (*ii) == nDisposeId )
150 			{
151 				(*ii) = 0;
152 			}
153 		}
154 
155 		if( !m_lstCallstack.empty()  && ! m_lstCallstack.front() )
156 		{
157 			// The thread is waiting for a disposed pCallerId, let it go
158 			osl_setCondition( m_cndWait );
159 		}
160 	}
161 
162 	void JobQueue::suspend()
163 	{
164 		MutexGuard guard( m_mutex );
165 		m_bSuspended = sal_True;
166 	}
167 
168 	void JobQueue::resume()
169 	{
170 		MutexGuard guard( m_mutex );
171 		m_bSuspended = sal_False;
172 		if( ! m_lstJob.empty() )
173 		{
174 			osl_setCondition( m_cndWait );
175 		}
176 	}
177 
178 	sal_Bool JobQueue::isEmpty()
179 	{
180 		MutexGuard guard( m_mutex );
181 		return m_lstJob.empty();
182 	}
183 
184 	sal_Bool JobQueue::isCallstackEmpty()
185 	{
186 		MutexGuard guard( m_mutex );
187 		return m_lstCallstack.empty();
188 	}
189 
190 	sal_Bool JobQueue::isBusy()
191 	{
192 		return m_nToDo > 0;
193 	}
194 
195 
196 }
197