Handle non-hardware X events correctly with native USER
[wine/multimedia.git] / scheduler / synchro.c
blobf7ba3817280fe9b84ca50bc6a637521f59869674
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 "syslevel.h"
17 #include "server.h"
18 #include "debug.h"
20 /***********************************************************************
21 * SYNC_BuildWaitStruct
23 static BOOL32 SYNC_BuildWaitStruct( DWORD count, const HANDLE32 *handles,
24 BOOL32 wait_all, BOOL32 wait_msg,
25 WAIT_STRUCT *wait )
27 DWORD i;
28 K32OBJ **ptr;
30 SYSTEM_LOCK();
31 wait->count = count;
32 wait->signaled = WAIT_FAILED;
33 wait->wait_all = wait_all;
34 wait->wait_msg = wait_msg;
35 for (i = 0, ptr = wait->objs; i < count; i++, ptr++)
37 if (!(*ptr = HANDLE_GetObjPtr( PROCESS_Current(), handles[i],
38 K32OBJ_UNKNOWN, SYNCHRONIZE,
39 &wait->server[i] )))
41 ERR(win32, "Bad handle %08x\n", handles[i]);
42 break;
44 if (!K32OBJ_OPS( *ptr )->signaled)
46 /* This object type cannot be waited upon */
47 ERR(win32, "Cannot wait on handle %08x\n", handles[i]);
48 K32OBJ_DecCount( *ptr );
49 break;
53 if (i != count)
55 /* There was an error */
56 wait->wait_msg = FALSE;
57 while (i--) K32OBJ_DecCount( wait->objs[i] );
59 SYSTEM_UNLOCK();
60 return (i == count);
64 /***********************************************************************
65 * SYNC_FreeWaitStruct
67 static void SYNC_FreeWaitStruct( WAIT_STRUCT *wait )
69 DWORD i;
70 K32OBJ **ptr;
71 SYSTEM_LOCK();
72 wait->wait_msg = FALSE;
73 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
74 K32OBJ_DecCount( *ptr );
75 SYSTEM_UNLOCK();
79 /***********************************************************************
80 * SYNC_CheckCondition
82 static BOOL32 SYNC_CheckCondition( WAIT_STRUCT *wait, DWORD thread_id )
84 DWORD i;
85 K32OBJ **ptr;
87 SYSTEM_LOCK();
88 if (wait->wait_all)
90 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
92 if (!K32OBJ_OPS( *ptr )->signaled( *ptr, thread_id ))
94 SYSTEM_UNLOCK();
95 return FALSE;
98 /* Wait satisfied: tell it to all objects */
99 wait->signaled = WAIT_OBJECT_0;
100 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
101 if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
102 wait->signaled = WAIT_ABANDONED_0;
103 SYSTEM_UNLOCK();
104 return TRUE;
106 else
108 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
110 if (K32OBJ_OPS( *ptr )->signaled( *ptr, thread_id ))
112 /* Wait satisfied: tell it to the object */
113 wait->signaled = WAIT_OBJECT_0 + i;
114 if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
115 wait->signaled = WAIT_ABANDONED_0 + i;
116 SYSTEM_UNLOCK();
117 return TRUE;
120 SYSTEM_UNLOCK();
121 return FALSE;
126 /***********************************************************************
127 * SYNC_WaitForCondition
129 void SYNC_WaitForCondition( WAIT_STRUCT *wait, DWORD timeout )
131 DWORD i, thread_id = GetCurrentThreadId();
132 LONG count;
133 K32OBJ **ptr;
134 sigset_t set;
136 SYSTEM_LOCK();
137 if (SYNC_CheckCondition( wait, thread_id ))
138 goto done; /* Condition already satisfied */
139 if (!timeout)
141 /* No need to wait */
142 wait->signaled = WAIT_TIMEOUT;
143 goto done;
146 /* Add ourselves to the waiting list of all objects */
148 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
149 K32OBJ_OPS( *ptr )->add_wait( *ptr, thread_id );
151 /* Release the system lock completely */
153 count = SYSTEM_LOCK_COUNT();
154 for (i = count; i > 0; i--) SYSTEM_UNLOCK();
156 /* Now wait for it */
158 TRACE(win32, "starting wait (%p %04x)\n",
159 THREAD_Current(), THREAD_Current()->teb_sel );
161 sigprocmask( SIG_SETMASK, NULL, &set );
162 sigdelset( &set, SIGUSR1 );
163 sigdelset( &set, SIGALRM );
164 if (timeout != INFINITE32)
166 while (wait->signaled == WAIT_FAILED)
168 struct itimerval timer;
169 DWORD start_ticks, elapsed;
170 timer.it_interval.tv_sec = timer.it_interval.tv_usec = 0;
171 timer.it_value.tv_sec = timeout / 1000;
172 timer.it_value.tv_usec = (timeout % 1000) * 1000;
173 start_ticks = GetTickCount();
174 setitimer( ITIMER_REAL, &timer, NULL );
175 sigsuspend( &set );
176 if (wait->signaled != WAIT_FAILED) break;
177 /* Recompute the timer value */
178 elapsed = GetTickCount() - start_ticks;
179 if (elapsed >= timeout) wait->signaled = WAIT_TIMEOUT;
180 else timeout -= elapsed;
183 else
185 while (wait->signaled == WAIT_FAILED)
187 sigsuspend( &set );
191 /* Grab the system lock again */
193 while (count--) SYSTEM_LOCK();
194 TRACE(win32, "wait finished (%p %04x)\n",
195 THREAD_Current(), THREAD_Current()->teb_sel );
197 /* Remove ourselves from the lists */
199 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
200 K32OBJ_OPS( *ptr )->remove_wait( *ptr, thread_id );
202 done:
203 SYSTEM_UNLOCK();
207 /***********************************************************************
208 * SYNC_DummySigHandler
210 * Dummy signal handler
212 static void SYNC_DummySigHandler(void)
217 /***********************************************************************
218 * SYNC_SetupSignals
220 * Setup signal handlers for a new thread.
221 * FIXME: should merge with SIGNAL_Init.
223 void SYNC_SetupSignals(void)
225 sigset_t set;
226 SIGNAL_SetHandler( SIGUSR1, SYNC_DummySigHandler, 0 );
227 /* FIXME: conflicts with system timers */
228 SIGNAL_SetHandler( SIGALRM, SYNC_DummySigHandler, 0 );
229 sigemptyset( &set );
230 /* Make sure these are blocked by default */
231 sigaddset( &set, SIGUSR1 );
232 sigaddset( &set, SIGALRM );
233 sigprocmask( SIG_BLOCK , &set, NULL);
237 /***********************************************************************
238 * SYNC_WakeUp
240 void SYNC_WakeUp( THREAD_QUEUE *wait_queue, DWORD max )
242 THREAD_ENTRY *entry;
244 if (!max) max = INFINITE32;
245 SYSTEM_LOCK();
246 if (!*wait_queue)
248 SYSTEM_UNLOCK();
249 return;
251 entry = (*wait_queue)->next;
252 for (;;)
254 THDB *thdb = entry->thread;
255 if (SYNC_CheckCondition( &thdb->wait_struct, THDB_TO_THREAD_ID(thdb) ))
257 TRACE(win32, "waking up %04x (pid %d)\n", thdb->teb_sel, thdb->unix_pid );
258 if (thdb->unix_pid)
259 kill( thdb->unix_pid, SIGUSR1 );
260 else
261 FIXME(win32,"have got unix_pid 0\n");
262 if (!--max) break;
264 if (entry == *wait_queue) break;
265 entry = entry->next;
267 SYSTEM_UNLOCK();
270 /***********************************************************************
271 * SYNC_MsgWakeUp
273 void SYNC_MsgWakeUp( THDB *thdb )
275 SYSTEM_LOCK();
277 if (!thdb)
279 SYSTEM_UNLOCK();
280 return;
283 if (thdb->wait_struct.wait_msg)
285 thdb->wait_struct.signaled = thdb->wait_struct.count;
287 TRACE(win32, "waking up %04x for message\n", thdb->teb_sel );
288 if (thdb->unix_pid)
289 kill( thdb->unix_pid, SIGUSR1 );
290 else
291 FIXME(win32,"have got unix_pid 0\n");
294 SYSTEM_UNLOCK();
297 /***********************************************************************
298 * SYNC_DoWait
300 DWORD SYNC_DoWait( DWORD count, const HANDLE32 *handles,
301 BOOL32 wait_all, DWORD timeout,
302 BOOL32 alertable, BOOL32 wait_msg )
304 WAIT_STRUCT *wait = &THREAD_Current()->wait_struct;
306 if (count > MAXIMUM_WAIT_OBJECTS)
308 SetLastError( ERROR_INVALID_PARAMETER );
309 return WAIT_FAILED;
312 if (alertable)
313 FIXME(win32, "alertable not implemented\n" );
315 SYSTEM_LOCK();
316 if (!SYNC_BuildWaitStruct( count, handles, wait_all, wait_msg, wait ))
317 wait->signaled = WAIT_FAILED;
318 else
320 int i;
321 /* Check if we can use a server wait */
322 for (i = 0; i < count; i++)
323 if (wait->server[i] == -1) break;
324 if (i == count)
326 int flags = 0;
327 SYSTEM_UNLOCK();
328 if (wait_all) flags |= SELECT_ALL;
329 if (alertable) flags |= SELECT_ALERTABLE;
330 if (wait_msg) flags |= SELECT_MSG;
331 if (timeout != INFINITE32) flags |= SELECT_TIMEOUT;
332 return CLIENT_Select( count, wait->server, flags, timeout );
334 else
336 /* Now wait for it */
337 SYNC_WaitForCondition( wait, timeout );
338 SYNC_FreeWaitStruct( wait );
341 SYSTEM_UNLOCK();
342 return wait->signaled;
345 /***********************************************************************
346 * Sleep (KERNEL32.679)
348 VOID WINAPI Sleep( DWORD timeout )
350 SYNC_DoWait( 0, NULL, FALSE, timeout, FALSE, FALSE );
353 /******************************************************************************
354 * SleepEx (KERNEL32.680)
356 DWORD WINAPI SleepEx( DWORD timeout, BOOL32 alertable )
358 DWORD ret = SYNC_DoWait( 0, NULL, FALSE, timeout, alertable, FALSE );
359 if (ret != WAIT_IO_COMPLETION) ret = 0;
360 return ret;
364 /***********************************************************************
365 * WaitForSingleObject (KERNEL32.723)
367 DWORD WINAPI WaitForSingleObject( HANDLE32 handle, DWORD timeout )
369 return SYNC_DoWait( 1, &handle, FALSE, timeout, FALSE, FALSE );
373 /***********************************************************************
374 * WaitForSingleObjectEx (KERNEL32.724)
376 DWORD WINAPI WaitForSingleObjectEx( HANDLE32 handle, DWORD timeout,
377 BOOL32 alertable )
379 return SYNC_DoWait( 1, &handle, FALSE, timeout, alertable, FALSE );
383 /***********************************************************************
384 * WaitForMultipleObjects (KERNEL32.721)
386 DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE32 *handles,
387 BOOL32 wait_all, DWORD timeout )
389 return SYNC_DoWait( count, handles, wait_all, timeout, FALSE, FALSE );
393 /***********************************************************************
394 * WaitForMultipleObjectsEx (KERNEL32.722)
396 DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE32 *handles,
397 BOOL32 wait_all, DWORD timeout,
398 BOOL32 alertable )
400 return SYNC_DoWait( count, handles, wait_all, timeout, alertable, FALSE );
404 /***********************************************************************
405 * WIN16_WaitForSingleObject (KERNEL.460)
407 DWORD WINAPI WIN16_WaitForSingleObject( HANDLE32 handle, DWORD timeout )
409 DWORD retval;
411 SYSLEVEL_ReleaseWin16Lock();
412 retval = WaitForSingleObject( handle, timeout );
413 SYSLEVEL_RestoreWin16Lock();
415 return retval;
418 /***********************************************************************
419 * WIN16_WaitForMultipleObjects (KERNEL.461)
421 DWORD WINAPI WIN16_WaitForMultipleObjects( DWORD count, const HANDLE32 *handles,
422 BOOL32 wait_all, DWORD timeout )
424 DWORD retval;
426 SYSLEVEL_ReleaseWin16Lock();
427 retval = WaitForMultipleObjects( count, handles, wait_all, timeout );
428 SYSLEVEL_RestoreWin16Lock();
430 return retval;