Release 980601
[wine/multimedia.git] / scheduler / synchro.c
blobbb4a1106ded3d249dbb522f7ddc6b70ff80a0ea7
1 /*
2 * Win32 process and thread synchronisation
4 * Copyright 1997 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <signal.h>
9 #include <sys/time.h>
10 #include <unistd.h>
11 #include "k32obj.h"
12 #include "heap.h"
13 #include "process.h"
14 #include "thread.h"
15 #include "winerror.h"
16 #include "debug.h"
18 /***********************************************************************
19 * SYNC_BuildWaitStruct
21 static BOOL32 SYNC_BuildWaitStruct( DWORD count, const HANDLE32 *handles,
22 BOOL32 wait_all, WAIT_STRUCT *wait )
24 DWORD i;
25 K32OBJ **ptr;
27 wait->count = count;
28 wait->signaled = WAIT_FAILED;
29 wait->wait_all = wait_all;
30 SYSTEM_LOCK();
31 for (i = 0, ptr = wait->objs; i < count; i++, ptr++)
33 if (!(*ptr = HANDLE_GetObjPtr( PROCESS_Current(), handles[i],
34 K32OBJ_UNKNOWN, SYNCHRONIZE )))
35 break;
36 if (!K32OBJ_OPS( *ptr )->signaled)
38 /* This object type cannot be waited upon */
39 K32OBJ_DecCount( *ptr );
40 break;
44 if (i != count)
46 /* There was an error */
47 while (i--) K32OBJ_DecCount( wait->objs[i] );
49 SYSTEM_UNLOCK();
50 return (i == count);
54 /***********************************************************************
55 * SYNC_FreeWaitStruct
57 static void SYNC_FreeWaitStruct( WAIT_STRUCT *wait )
59 DWORD i;
60 K32OBJ **ptr;
61 SYSTEM_LOCK();
62 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
63 K32OBJ_DecCount( *ptr );
64 SYSTEM_UNLOCK();
68 /***********************************************************************
69 * SYNC_CheckCondition
71 static BOOL32 SYNC_CheckCondition( WAIT_STRUCT *wait, DWORD thread_id )
73 DWORD i;
74 K32OBJ **ptr;
76 SYSTEM_LOCK();
77 if (wait->wait_all)
79 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
81 if (!K32OBJ_OPS( *ptr )->signaled( *ptr, thread_id ))
83 SYSTEM_UNLOCK();
84 return FALSE;
87 /* Wait satisfied: tell it to all objects */
88 wait->signaled = WAIT_OBJECT_0;
89 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
90 if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
91 wait->signaled = WAIT_ABANDONED_0;
92 SYSTEM_UNLOCK();
93 return TRUE;
95 else
97 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
99 if (K32OBJ_OPS( *ptr )->signaled( *ptr, thread_id ))
101 /* Wait satisfied: tell it to the object */
102 wait->signaled = WAIT_OBJECT_0 + i;
103 if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
104 wait->signaled = WAIT_ABANDONED_0 + i;
105 SYSTEM_UNLOCK();
106 return TRUE;
109 SYSTEM_UNLOCK();
110 return FALSE;
115 /***********************************************************************
116 * SYNC_WaitForCondition
118 void SYNC_WaitForCondition( WAIT_STRUCT *wait, DWORD timeout )
120 DWORD i, thread_id = GetCurrentThreadId();
121 LONG count;
122 K32OBJ **ptr;
123 sigset_t set;
125 SYSTEM_LOCK();
126 if (SYNC_CheckCondition( wait, thread_id ))
127 goto done; /* Condition already satisfied */
128 if (!timeout)
130 /* No need to wait */
131 wait->signaled = WAIT_TIMEOUT;
132 goto done;
135 /* Add ourselves to the waiting list of all objects */
137 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
138 K32OBJ_OPS( *ptr )->add_wait( *ptr, thread_id );
140 /* Release the system lock completely */
142 count = SYSTEM_LOCK_COUNT();
143 for (i = count; i > 0; i--) SYSTEM_UNLOCK();
145 /* Now wait for it */
147 TRACE(win32, "starting wait (%p %04x)\n",
148 THREAD_Current(), THREAD_Current()->teb_sel );
150 sigprocmask( SIG_SETMASK, NULL, &set );
151 sigdelset( &set, SIGUSR1 );
152 sigdelset( &set, SIGALRM );
153 if (timeout != INFINITE32)
155 while (wait->signaled == WAIT_FAILED)
157 struct itimerval timer;
158 DWORD start_ticks, elapsed;
159 timer.it_interval.tv_sec = timer.it_interval.tv_usec = 0;
160 timer.it_value.tv_sec = timeout / 1000;
161 timer.it_value.tv_usec = (timeout % 1000) * 1000;
162 start_ticks = GetTickCount();
163 setitimer( ITIMER_REAL, &timer, NULL );
164 sigsuspend( &set );
165 if (wait->signaled != WAIT_FAILED) break;
166 /* Recompute the timer value */
167 elapsed = GetTickCount() - start_ticks;
168 if (elapsed >= timeout) wait->signaled = WAIT_TIMEOUT;
169 else timeout -= elapsed;
172 else
174 while (wait->signaled == WAIT_FAILED)
176 sigsuspend( &set );
180 /* Grab the system lock again */
182 while (count--) SYSTEM_LOCK();
183 TRACE(win32, "wait finished (%p %04x)\n",
184 THREAD_Current(), THREAD_Current()->teb_sel );
186 /* Remove ourselves from the lists */
188 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
189 K32OBJ_OPS( *ptr )->remove_wait( *ptr, thread_id );
191 done:
192 SYSTEM_UNLOCK();
196 /***********************************************************************
197 * SYNC_DummySigHandler
199 * Dummy signal handler
201 static void SYNC_DummySigHandler(void)
206 /***********************************************************************
207 * SYNC_SetupSignals
209 * Setup signal handlers for a new thread.
210 * FIXME: should merge with SIGNAL_Init.
212 void SYNC_SetupSignals(void)
214 sigset_t set;
215 SIGNAL_SetHandler( SIGUSR1, SYNC_DummySigHandler, 0 );
216 /* FIXME: conflicts with system timers */
217 SIGNAL_SetHandler( SIGALRM, SYNC_DummySigHandler, 0 );
218 sigemptyset( &set );
219 /* Make sure these are blocked by default */
220 sigaddset( &set, SIGUSR1 );
221 sigaddset( &set, SIGALRM );
222 sigprocmask( SIG_BLOCK , &set, NULL);
226 /***********************************************************************
227 * SYNC_WakeUp
229 void SYNC_WakeUp( THREAD_QUEUE *wait_queue, DWORD max )
231 THREAD_ENTRY *entry;
233 if (!max) max = INFINITE32;
234 SYSTEM_LOCK();
235 if (!*wait_queue)
237 SYSTEM_UNLOCK();
238 return;
240 entry = (*wait_queue)->next;
241 for (;;)
243 THDB *thdb = entry->thread;
244 if (SYNC_CheckCondition( &thdb->wait_struct, THDB_TO_THREAD_ID(thdb) ))
246 TRACE(win32, "waking up %04x\n", thdb->teb_sel );
247 if (thdb->unix_pid)
248 kill( thdb->unix_pid, SIGUSR1 );
249 else
250 FIXME(win32,"have got unix_pid 0\n");
251 if (!--max) break;
253 if (entry == *wait_queue) break;
254 entry = entry->next;
256 SYSTEM_UNLOCK();
260 /***********************************************************************
261 * WaitForSingleObject (KERNEL32.723)
263 DWORD WINAPI WaitForSingleObject( HANDLE32 handle, DWORD timeout )
265 return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE );
269 /***********************************************************************
270 * WaitForSingleObjectEx (KERNEL32.724)
272 DWORD WINAPI WaitForSingleObjectEx( HANDLE32 handle, DWORD timeout,
273 BOOL32 alertable )
275 return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, alertable );
279 /***********************************************************************
280 * WaitForMultipleObjects (KERNEL32.721)
282 DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE32 *handles,
283 BOOL32 wait_all, DWORD timeout )
285 return WaitForMultipleObjectsEx(count, handles, wait_all, timeout, FALSE);
289 /***********************************************************************
290 * WaitForMultipleObjectsEx (KERNEL32.722)
292 DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE32 *handles,
293 BOOL32 wait_all, DWORD timeout,
294 BOOL32 alertable )
296 WAIT_STRUCT *wait = &THREAD_Current()->wait_struct;
298 if (count > MAXIMUM_WAIT_OBJECTS)
300 SetLastError( ERROR_INVALID_PARAMETER );
301 return WAIT_FAILED;
304 if (alertable)
305 FIXME(win32, "alertable not implemented\n" );
307 SYSTEM_LOCK();
308 if (!SYNC_BuildWaitStruct( count, handles, wait_all, wait ))
309 wait->signaled = WAIT_FAILED;
310 else
312 /* Now wait for it */
313 SYNC_WaitForCondition( wait, timeout );
314 SYNC_FreeWaitStruct( wait );
316 SYSTEM_UNLOCK();
317 return wait->signaled;