Release 980215
[wine/multimedia.git] / scheduler / synchro.c
blob4195fc2011faf7039ffdca258e49ca8e82914715
1 /*
2 * Win32 process and thread synchronisation
4 * Copyright 1997 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <sys/time.h>
11 #include <unistd.h>
12 #include "k32obj.h"
13 #include "heap.h"
14 #include "process.h"
15 #include "thread.h"
16 #include "winerror.h"
17 #include "stddebug.h"
18 #include "debug.h"
20 /***********************************************************************
21 * SYNC_BuildWaitStruct
23 static BOOL32 SYNC_BuildWaitStruct( DWORD count, const HANDLE32 *handles,
24 BOOL32 wait_all, WAIT_STRUCT *wait )
26 DWORD i;
27 K32OBJ **ptr;
29 wait->count = count;
30 wait->signaled = WAIT_FAILED;
31 wait->wait_all = wait_all;
32 SYSTEM_LOCK();
33 for (i = 0, ptr = wait->objs; i < count; i++, ptr++)
35 if (!(*ptr = HANDLE_GetObjPtr( handles[i], K32OBJ_UNKNOWN,
36 SYNCHRONIZE )))
37 break;
38 if (!K32OBJ_OPS( *ptr )->signaled)
40 /* This object type cannot be waited upon */
41 K32OBJ_DecCount( *ptr );
42 break;
46 if (i != count)
48 /* There was an error */
49 while (i--) K32OBJ_DecCount( wait->objs[i] );
51 SYSTEM_UNLOCK();
52 return (i == count);
56 /***********************************************************************
57 * SYNC_FreeWaitStruct
59 static void SYNC_FreeWaitStruct( WAIT_STRUCT *wait )
61 DWORD i;
62 K32OBJ **ptr;
63 SYSTEM_LOCK();
64 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
65 K32OBJ_DecCount( *ptr );
66 SYSTEM_UNLOCK();
70 /***********************************************************************
71 * SYNC_CheckCondition
73 static BOOL32 SYNC_CheckCondition( WAIT_STRUCT *wait, DWORD thread_id )
75 DWORD i;
76 K32OBJ **ptr;
78 SYSTEM_LOCK();
79 if (wait->wait_all)
81 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
83 if (!K32OBJ_OPS( *ptr )->signaled( *ptr, thread_id ))
85 SYSTEM_UNLOCK();
86 return FALSE;
89 /* Wait satisfied: tell it to all objects */
90 wait->signaled = WAIT_OBJECT_0;
91 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
92 if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
93 wait->signaled = WAIT_ABANDONED_0;
94 SYSTEM_UNLOCK();
95 return TRUE;
97 else
99 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
101 if (K32OBJ_OPS( *ptr )->signaled( *ptr, thread_id ))
103 /* Wait satisfied: tell it to the object */
104 wait->signaled = WAIT_OBJECT_0 + i;
105 if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
106 wait->signaled = WAIT_ABANDONED_0 + i;
107 SYSTEM_UNLOCK();
108 return TRUE;
111 SYSTEM_UNLOCK();
112 return FALSE;
117 /***********************************************************************
118 * SYNC_WaitForCondition
120 void SYNC_WaitForCondition( WAIT_STRUCT *wait, DWORD timeout )
122 DWORD i, thread_id = GetCurrentThreadId();
123 LONG count;
124 K32OBJ **ptr;
125 sigset_t set;
127 SYSTEM_LOCK();
128 if (SYNC_CheckCondition( wait, thread_id ))
129 goto done; /* Condition already satisfied */
130 if (!timeout)
132 /* No need to wait */
133 wait->signaled = WAIT_TIMEOUT;
134 goto done;
137 /* Add ourselves to the waiting list of all objects */
139 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
140 K32OBJ_OPS( *ptr )->add_wait( *ptr, thread_id );
142 /* Release the system lock completely */
144 count = SYSTEM_LOCK_COUNT();
145 for (i = count; i > 0; i--) SYSTEM_UNLOCK();
147 /* Now wait for it */
149 dprintf_win32( stddeb, "SYNC: starting wait (%p %04x)\n",
150 THREAD_Current(), THREAD_Current()->teb_sel );
152 sigprocmask( SIG_SETMASK, NULL, &set );
153 sigdelset( &set, SIGUSR1 );
154 sigdelset( &set, SIGALRM );
155 if (timeout != INFINITE32)
157 while (wait->signaled == WAIT_FAILED)
159 struct itimerval timer;
160 DWORD start_ticks, elapsed;
161 timer.it_interval.tv_sec = timer.it_interval.tv_usec = 0;
162 timer.it_value.tv_sec = timeout / 1000;
163 timer.it_value.tv_usec = (timeout % 1000) * 1000;
164 start_ticks = GetTickCount();
165 setitimer( ITIMER_REAL, &timer, NULL );
166 sigsuspend( &set );
167 if (wait->signaled != WAIT_FAILED) break;
168 /* Recompute the timer value */
169 elapsed = GetTickCount() - start_ticks;
170 if (elapsed >= timeout) wait->signaled = WAIT_TIMEOUT;
171 else timeout -= elapsed;
174 else
176 while (wait->signaled == WAIT_FAILED)
178 sigsuspend( &set );
182 /* Grab the system lock again */
184 while (count--) SYSTEM_LOCK();
185 dprintf_win32( stddeb, "SYNC: wait finished (%p %04x)\n",
186 THREAD_Current(), THREAD_Current()->teb_sel );
188 /* Remove ourselves from the lists */
190 for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
191 K32OBJ_OPS( *ptr )->remove_wait( *ptr, thread_id );
193 done:
194 SYSTEM_UNLOCK();
198 /***********************************************************************
199 * SYNC_DummySigHandler
201 * Dummy signal handler
203 static void SYNC_DummySigHandler(void)
208 /***********************************************************************
209 * SYNC_SetupSignals
211 * Setup signal handlers for a new thread.
212 * FIXME: should merge with SIGNAL_Init.
214 void SYNC_SetupSignals(void)
216 sigset_t set;
217 SIGNAL_SetHandler( SIGUSR1, SYNC_DummySigHandler, 0 );
218 /* FIXME: conflicts with system timers */
219 SIGNAL_SetHandler( SIGALRM, SYNC_DummySigHandler, 0 );
220 sigemptyset( &set );
221 /* Make sure these are blocked by default */
222 sigaddset( &set, SIGUSR1 );
223 sigaddset( &set, SIGALRM );
224 sigprocmask( SIG_BLOCK , &set, NULL);
228 /***********************************************************************
229 * SYNC_WakeUp
231 void SYNC_WakeUp( THREAD_QUEUE *wait_queue, DWORD max )
233 THREAD_ENTRY *entry;
235 if (!max) max = INFINITE32;
236 SYSTEM_LOCK();
237 if (!*wait_queue)
239 SYSTEM_UNLOCK();
240 return;
242 entry = (*wait_queue)->next;
243 for (;;)
245 THDB *thdb = entry->thread;
246 if (SYNC_CheckCondition( &thdb->wait_struct, THDB_TO_THREAD_ID(thdb) ))
248 dprintf_win32( stddeb, "SYNC: waking up %04x\n", thdb->teb_sel );
249 kill( thdb->unix_pid, SIGUSR1 );
250 if (!--max) break;
252 if (entry == *wait_queue) break;
253 entry = entry->next;
255 SYSTEM_UNLOCK();
259 /***********************************************************************
260 * WaitForSingleObject (KERNEL32.723)
262 DWORD WINAPI WaitForSingleObject( HANDLE32 handle, DWORD timeout )
264 return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE );
268 /***********************************************************************
269 * WaitForSingleObjectEx (KERNEL32.724)
271 DWORD WINAPI WaitForSingleObjectEx( HANDLE32 handle, DWORD timeout,
272 BOOL32 alertable )
274 return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, alertable );
278 /***********************************************************************
279 * WaitForMultipleObjects (KERNEL32.721)
281 DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE32 *handles,
282 BOOL32 wait_all, DWORD timeout )
284 return WaitForMultipleObjectsEx(count, handles, wait_all, timeout, FALSE);
288 /***********************************************************************
289 * WaitForMultipleObjectsEx (KERNEL32.722)
291 DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE32 *handles,
292 BOOL32 wait_all, DWORD timeout,
293 BOOL32 alertable )
295 WAIT_STRUCT *wait = &THREAD_Current()->wait_struct;
297 if (count > MAXIMUM_WAIT_OBJECTS)
299 SetLastError( ERROR_INVALID_PARAMETER );
300 return WAIT_FAILED;
303 if (alertable)
304 fprintf( stderr,
305 "WaitForMultipleObjectEx: 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;