WINE_UNICODE_TEXT was incorrect.
[wine] / scheduler / synchro.c
1 /*
2  * Win32 process and thread synchronisation
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <sys/time.h>
11 #include <unistd.h>
12
13 #include "file.h"  /* for DOSFS_UnixTimeToFileTime */
14 #include "thread.h"
15 #include "winerror.h"
16 #include "server.h"
17
18
19 /***********************************************************************
20  *              get_timeout
21  */
22 inline static void get_timeout( struct timeval *when, int timeout )
23 {
24     gettimeofday( when, 0 );
25     if (timeout)
26     {
27         long sec = timeout / 1000;
28         if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
29         {
30             when->tv_usec -= 1000000;
31             when->tv_sec++;
32         }
33         when->tv_sec += sec;
34     }
35 }
36
37
38 /***********************************************************************
39  *              wait_reply
40  *
41  * Wait for a reply on the waiting pipe of the current thread.
42  */
43 static int wait_reply(void)
44 {
45     int signaled;
46     for (;;)
47     {
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");
55     }
56     /* the server closed the connection; time to die... */
57     SYSDEPS_ExitThread(0);
58 }
59
60
61 /***********************************************************************
62  *              call_apcs
63  *
64  * Call outstanding APCs.
65  */
66 static void call_apcs( BOOL alertable )
67 {
68     FARPROC proc = NULL;
69     FILETIME ft;
70     void *args[4];
71
72     for (;;)
73     {
74         int type = APC_NONE;
75         SERVER_START_VAR_REQ( get_apc, sizeof(args) )
76         {
77             req->alertable = alertable;
78             if (!SERVER_CALL())
79             {
80                 type = req->type;
81                 proc = req->func;
82                 memcpy( args, server_data_ptr(req), server_data_size(req) );
83             }
84         }
85         SERVER_END_VAR_REQ;
86
87         switch(type)
88         {
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;
105         }
106     }
107 }
108
109 /***********************************************************************
110  *              Sleep  (KERNEL32.679)
111  */
112 VOID WINAPI Sleep( DWORD timeout )
113 {
114     WaitForMultipleObjectsEx( 0, NULL, FALSE, timeout, FALSE );
115 }
116
117 /******************************************************************************
118  *              SleepEx   (KERNEL32.680)
119  */
120 DWORD WINAPI SleepEx( DWORD timeout, BOOL alertable )
121 {
122     DWORD ret = WaitForMultipleObjectsEx( 0, NULL, FALSE, timeout, alertable );
123     if (ret != WAIT_IO_COMPLETION) ret = 0;
124     return ret;
125 }
126
127
128 /***********************************************************************
129  *           WaitForSingleObject   (KERNEL32.723)
130  */
131 DWORD WINAPI WaitForSingleObject( HANDLE handle, DWORD timeout )
132 {
133     return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE );
134 }
135
136
137 /***********************************************************************
138  *           WaitForSingleObjectEx   (KERNEL32.724)
139  */
140 DWORD WINAPI WaitForSingleObjectEx( HANDLE handle, DWORD timeout,
141                                     BOOL alertable )
142 {
143     return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, alertable );
144 }
145
146
147 /***********************************************************************
148  *           WaitForMultipleObjects   (KERNEL32.721)
149  */
150 DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles,
151                                      BOOL wait_all, DWORD timeout )
152 {
153     return WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
154 }
155
156
157 /***********************************************************************
158  *           WaitForMultipleObjectsEx   (KERNEL32.722)
159  */
160 DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
161                                        BOOL wait_all, DWORD timeout,
162                                        BOOL alertable )
163 {
164     int i, ret;
165     struct timeval tv;
166
167     if (count > MAXIMUM_WAIT_OBJECTS)
168     {
169         SetLastError( ERROR_INVALID_PARAMETER );
170         return WAIT_FAILED;
171     }
172
173     if (timeout == INFINITE) tv.tv_sec = tv.tv_usec = 0;
174     else get_timeout( &tv, timeout );
175
176     for (;;)
177     {
178         SERVER_START_VAR_REQ( select, count * sizeof(int) )
179         {
180             int *data = server_data_ptr( req );
181
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];
186
187             if (wait_all) req->flags |= SELECT_ALL;
188             if (alertable) req->flags |= SELECT_ALERTABLE;
189             if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT;
190
191             ret = SERVER_CALL();
192         }
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;
198     }
199     if (HIWORD(ret))  /* is it an error code? */
200     {
201         SetLastError( RtlNtStatusToDosError(ret) );
202         ret = WAIT_FAILED;
203     }
204     return ret;
205 }
206
207
208 /***********************************************************************
209  *           WaitForSingleObject16   (KERNEL.460)
210  */
211 DWORD WINAPI WaitForSingleObject16( HANDLE handle, DWORD timeout )
212 {
213     DWORD retval, mutex_count;
214
215     ReleaseThunkLock( &mutex_count );
216     retval = WaitForSingleObject( handle, timeout );
217     RestoreThunkLock( mutex_count );
218     return retval;
219 }
220
221 /***********************************************************************
222  *           WaitForMultipleObjects16   (KERNEL.461)
223  */
224 DWORD WINAPI WaitForMultipleObjects16( DWORD count, const HANDLE *handles,
225                                        BOOL wait_all, DWORD timeout )
226 {
227     DWORD retval, mutex_count;
228
229     ReleaseThunkLock( &mutex_count );
230     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
231     RestoreThunkLock( mutex_count );
232     return retval;
233 }
234
235 /***********************************************************************
236  *           WaitForMultipleObjectsEx16   (KERNEL.495)
237  */
238 DWORD WINAPI WaitForMultipleObjectsEx16( DWORD count, const HANDLE *handles,
239                                          BOOL wait_all, DWORD timeout, BOOL alertable )
240 {
241     DWORD retval, mutex_count;
242
243     ReleaseThunkLock( &mutex_count );
244     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, alertable );
245     RestoreThunkLock( mutex_count );
246     return retval;
247 }