2 * Win32 process and thread synchronisation
4 * Copyright 1997 Alexandre Julliard
18 /***********************************************************************
19 * SYNC_BuildWaitStruct
21 static BOOL32
SYNC_BuildWaitStruct( DWORD count
, const HANDLE32
*handles
,
22 BOOL32 wait_all
, WAIT_STRUCT
*wait
)
28 wait
->signaled
= WAIT_FAILED
;
29 wait
->wait_all
= wait_all
;
31 for (i
= 0, ptr
= wait
->objs
; i
< count
; i
++, ptr
++)
33 if (!(*ptr
= HANDLE_GetObjPtr( PROCESS_Current(), handles
[i
],
34 K32OBJ_UNKNOWN
, SYNCHRONIZE
)))
36 if (!K32OBJ_OPS( *ptr
)->signaled
)
38 /* This object type cannot be waited upon */
39 K32OBJ_DecCount( *ptr
);
46 /* There was an error */
47 while (i
--) K32OBJ_DecCount( wait
->objs
[i
] );
54 /***********************************************************************
57 static void SYNC_FreeWaitStruct( WAIT_STRUCT
*wait
)
62 for (i
= 0, ptr
= wait
->objs
; i
< wait
->count
; i
++, ptr
++)
63 K32OBJ_DecCount( *ptr
);
68 /***********************************************************************
71 static BOOL32
SYNC_CheckCondition( WAIT_STRUCT
*wait
, DWORD thread_id
)
79 for (i
= 0, ptr
= wait
->objs
; i
< wait
->count
; i
++, ptr
++)
81 if (!K32OBJ_OPS( *ptr
)->signaled( *ptr
, thread_id
))
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
;
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
;
115 /***********************************************************************
116 * SYNC_WaitForCondition
118 void SYNC_WaitForCondition( WAIT_STRUCT
*wait
, DWORD timeout
)
120 DWORD i
, thread_id
= GetCurrentThreadId();
126 if (SYNC_CheckCondition( wait
, thread_id
))
127 goto done
; /* Condition already satisfied */
130 /* No need to wait */
131 wait
->signaled
= WAIT_TIMEOUT
;
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
);
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
;
174 while (wait
->signaled
== WAIT_FAILED
)
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
);
196 /***********************************************************************
197 * SYNC_DummySigHandler
199 * Dummy signal handler
201 static void SYNC_DummySigHandler(void)
206 /***********************************************************************
209 * Setup signal handlers for a new thread.
210 * FIXME: should merge with SIGNAL_Init.
212 void SYNC_SetupSignals(void)
215 SIGNAL_SetHandler( SIGUSR1
, SYNC_DummySigHandler
, 0 );
216 /* FIXME: conflicts with system timers */
217 SIGNAL_SetHandler( SIGALRM
, SYNC_DummySigHandler
, 0 );
219 /* Make sure these are blocked by default */
220 sigaddset( &set
, SIGUSR1
);
221 sigaddset( &set
, SIGALRM
);
222 sigprocmask( SIG_BLOCK
, &set
, NULL
);
226 /***********************************************************************
229 void SYNC_WakeUp( THREAD_QUEUE
*wait_queue
, DWORD max
)
233 if (!max
) max
= INFINITE32
;
240 entry
= (*wait_queue
)->next
;
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
);
248 kill( thdb
->unix_pid
, SIGUSR1
);
250 FIXME(win32
,"have got unix_pid 0\n");
253 if (entry
== *wait_queue
) break;
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
,
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
,
296 WAIT_STRUCT
*wait
= &THREAD_Current()->wait_struct
;
298 if (count
> MAXIMUM_WAIT_OBJECTS
)
300 SetLastError( ERROR_INVALID_PARAMETER
);
305 FIXME(win32
, "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
;