2 * Win32 process and thread synchronisation
4 * Copyright 1997 Alexandre Julliard
20 /***********************************************************************
21 * SYNC_BuildWaitStruct
23 static BOOL32
SYNC_BuildWaitStruct( DWORD count
, const HANDLE32
*handles
,
24 BOOL32 wait_all
, WAIT_STRUCT
*wait
)
30 wait
->signaled
= WAIT_FAILED
;
31 wait
->wait_all
= wait_all
;
33 for (i
= 0, ptr
= wait
->objs
; i
< count
; i
++, ptr
++)
35 if (!(*ptr
= HANDLE_GetObjPtr( handles
[i
], K32OBJ_UNKNOWN
,
38 if (!K32OBJ_OPS( *ptr
)->signaled
)
40 /* This object type cannot be waited upon */
41 K32OBJ_DecCount( *ptr
);
48 /* There was an error */
49 while (i
--) K32OBJ_DecCount( wait
->objs
[i
] );
56 /***********************************************************************
59 static void SYNC_FreeWaitStruct( WAIT_STRUCT
*wait
)
64 for (i
= 0, ptr
= wait
->objs
; i
< wait
->count
; i
++, ptr
++)
65 K32OBJ_DecCount( *ptr
);
70 /***********************************************************************
73 static BOOL32
SYNC_CheckCondition( WAIT_STRUCT
*wait
, DWORD thread_id
)
81 for (i
= 0, ptr
= wait
->objs
; i
< wait
->count
; i
++, ptr
++)
83 if (!K32OBJ_OPS( *ptr
)->signaled( *ptr
, thread_id
))
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
;
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
;
117 /***********************************************************************
118 * SYNC_WaitForCondition
120 void SYNC_WaitForCondition( WAIT_STRUCT
*wait
, DWORD timeout
)
122 DWORD i
, thread_id
= GetCurrentThreadId();
128 if (SYNC_CheckCondition( wait
, thread_id
))
129 goto done
; /* Condition already satisfied */
132 /* No need to wait */
133 wait
->signaled
= WAIT_TIMEOUT
;
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
);
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
;
176 while (wait
->signaled
== WAIT_FAILED
)
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
);
198 /***********************************************************************
199 * SYNC_DummySigHandler
201 * Dummy signal handler
203 static void SYNC_DummySigHandler(void)
208 /***********************************************************************
211 * Setup signal handlers for a new thread.
212 * FIXME: should merge with SIGNAL_Init.
214 void SYNC_SetupSignals(void)
217 SIGNAL_SetHandler( SIGUSR1
, SYNC_DummySigHandler
, 0 );
218 /* FIXME: conflicts with system timers */
219 SIGNAL_SetHandler( SIGALRM
, SYNC_DummySigHandler
, 0 );
221 /* Make sure these are blocked by default */
222 sigaddset( &set
, SIGUSR1
);
223 sigaddset( &set
, SIGALRM
);
224 sigprocmask( SIG_BLOCK
, &set
, NULL
);
228 /***********************************************************************
231 void SYNC_WakeUp( THREAD_QUEUE
*wait_queue
, DWORD max
)
235 if (!max
) max
= INFINITE32
;
242 entry
= (*wait_queue
)->next
;
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
);
252 if (entry
== *wait_queue
) break;
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
,
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
,
295 WAIT_STRUCT
*wait
= &THREAD_Current()->wait_struct
;
297 if (count
> MAXIMUM_WAIT_OBJECTS
)
299 SetLastError( ERROR_INVALID_PARAMETER
);
305 "WaitForMultipleObjectEx: alertable not implemented\n" );
308 if (!SYNC_BuildWaitStruct( count
, handles
, wait_all
, wait
))
309 wait
->signaled
= WAIT_FAILED
;
312 /* Now wait for it */
313 SYNC_WaitForCondition( wait
, timeout
);
314 SYNC_FreeWaitStruct( wait
);
317 return wait
->signaled
;