New set of macros for server calls; makes requests without variable
[wine/multimedia.git] / scheduler / synchro.c
blobca9afc3f3afcfc4f4b13999734b2cf18af978b6f
1 /*
2 * Win32 process and thread synchronisation
4 * Copyright 1997 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <sys/time.h>
11 #include <unistd.h>
13 #include "file.h" /* for DOSFS_UnixTimeToFileTime */
14 #include "thread.h"
15 #include "winerror.h"
16 #include "server.h"
19 /***********************************************************************
20 * get_timeout
22 inline static void get_timeout( struct timeval *when, int timeout )
24 gettimeofday( when, 0 );
25 if (timeout)
27 long sec = timeout / 1000;
28 if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
30 when->tv_usec -= 1000000;
31 when->tv_sec++;
33 when->tv_sec += sec;
38 /***********************************************************************
39 * wait_reply
41 * Wait for a reply on the waiting pipe of the current thread.
43 static int wait_reply(void)
45 int signaled;
46 for (;;)
48 int ret = read( NtCurrentTeb()->wait_fd, &signaled, sizeof(signaled) );
49 if (ret == sizeof(signaled)) return signaled;
50 if (!ret) break;
51 if (ret > 0) server_protocol_error( "partial wakeup read %d\n", ret );
52 if (errno == EINTR) continue;
53 if (errno == EPIPE) break;
54 server_protocol_perror("read");
56 /* the server closed the connection; time to die... */
57 SYSDEPS_ExitThread(0);
61 /***********************************************************************
62 * call_apcs
64 * Call outstanding APCs.
66 static void call_apcs( BOOL alertable )
68 FARPROC proc = NULL;
69 FILETIME ft;
70 void *args[4];
72 for (;;)
74 int type = APC_NONE;
75 SERVER_START_VAR_REQ( get_apc, sizeof(args) )
77 req->alertable = alertable;
78 if (!SERVER_CALL())
80 type = req->type;
81 proc = req->func;
82 memcpy( args, server_data_ptr(req), server_data_size(req) );
85 SERVER_END_VAR_REQ;
87 switch(type)
89 case APC_NONE:
90 return; /* no more APCs */
91 case APC_ASYNC:
92 proc( &args[0] );
93 break;
94 case APC_USER:
95 proc( args[0] );
96 break;
97 case APC_TIMER:
98 /* convert sec/usec to NT time */
99 DOSFS_UnixTimeToFileTime( (time_t)args[0], &ft, (DWORD)args[1] * 10 );
100 proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime );
101 break;
102 default:
103 server_protocol_error( "get_apc_request: bad type %d\n", type );
104 break;
109 /***********************************************************************
110 * Sleep (KERNEL32.679)
112 VOID WINAPI Sleep( DWORD timeout )
114 WaitForMultipleObjectsEx( 0, NULL, FALSE, timeout, FALSE );
117 /******************************************************************************
118 * SleepEx (KERNEL32.680)
120 DWORD WINAPI SleepEx( DWORD timeout, BOOL alertable )
122 DWORD ret = WaitForMultipleObjectsEx( 0, NULL, FALSE, timeout, alertable );
123 if (ret != WAIT_IO_COMPLETION) ret = 0;
124 return ret;
128 /***********************************************************************
129 * WaitForSingleObject (KERNEL32.723)
131 DWORD WINAPI WaitForSingleObject( HANDLE handle, DWORD timeout )
133 return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE );
137 /***********************************************************************
138 * WaitForSingleObjectEx (KERNEL32.724)
140 DWORD WINAPI WaitForSingleObjectEx( HANDLE handle, DWORD timeout,
141 BOOL alertable )
143 return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, alertable );
147 /***********************************************************************
148 * WaitForMultipleObjects (KERNEL32.721)
150 DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles,
151 BOOL wait_all, DWORD timeout )
153 return WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
157 /***********************************************************************
158 * WaitForMultipleObjectsEx (KERNEL32.722)
160 DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
161 BOOL wait_all, DWORD timeout,
162 BOOL alertable )
164 int i, ret;
165 struct timeval tv;
167 if (count > MAXIMUM_WAIT_OBJECTS)
169 SetLastError( ERROR_INVALID_PARAMETER );
170 return WAIT_FAILED;
173 if (timeout == INFINITE) tv.tv_sec = tv.tv_usec = 0;
174 else get_timeout( &tv, timeout );
176 for (;;)
178 SERVER_START_VAR_REQ( select, count * sizeof(int) )
180 int *data = server_data_ptr( req );
182 req->flags = SELECT_INTERRUPTIBLE;
183 req->sec = tv.tv_sec;
184 req->usec = tv.tv_usec;
185 for (i = 0; i < count; i++) data[i] = handles[i];
187 if (wait_all) req->flags |= SELECT_ALL;
188 if (alertable) req->flags |= SELECT_ALERTABLE;
189 if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT;
191 ret = SERVER_CALL();
193 SERVER_END_VAR_REQ;
194 if (ret == STATUS_PENDING) ret = wait_reply();
195 if (ret != STATUS_USER_APC) break;
196 call_apcs( alertable );
197 if (alertable) break;
199 if (HIWORD(ret)) /* is it an error code? */
201 SetLastError( RtlNtStatusToDosError(ret) );
202 ret = WAIT_FAILED;
204 return ret;
208 /***********************************************************************
209 * WaitForSingleObject16 (KERNEL.460)
211 DWORD WINAPI WaitForSingleObject16( HANDLE handle, DWORD timeout )
213 DWORD retval, mutex_count;
215 ReleaseThunkLock( &mutex_count );
216 retval = WaitForSingleObject( handle, timeout );
217 RestoreThunkLock( mutex_count );
218 return retval;
221 /***********************************************************************
222 * WaitForMultipleObjects16 (KERNEL.461)
224 DWORD WINAPI WaitForMultipleObjects16( DWORD count, const HANDLE *handles,
225 BOOL wait_all, DWORD timeout )
227 DWORD retval, mutex_count;
229 ReleaseThunkLock( &mutex_count );
230 retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
231 RestoreThunkLock( mutex_count );
232 return retval;
235 /***********************************************************************
236 * WaitForMultipleObjectsEx16 (KERNEL.495)
238 DWORD WINAPI WaitForMultipleObjectsEx16( DWORD count, const HANDLE *handles,
239 BOOL wait_all, DWORD timeout, BOOL alertable )
241 DWORD retval, mutex_count;
243 ReleaseThunkLock( &mutex_count );
244 retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, alertable );
245 RestoreThunkLock( mutex_count );
246 return retval;