3 Copyright 2003, 2004, 2005 Red Hat Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #ifdef __OUTSIDE_CYGWIN__
14 #define __BSD_VISIBLE 1
15 #include <sys/smallprint.h>
19 #include "cygserver_ipc.h"
21 /* A BSD kernel global mutex. */
25 mtx_init (mtx
*m
, const char *name
, const void *, int)
29 /* Can't use Windows Mutexes here since Windows Mutexes are only
30 unlockable by the lock owner. */
31 m
->h
= CreateSemaphore (NULL
, 1, 1, NULL
);
33 panic ("couldn't allocate %s mutex, %E\n", name
);
37 _mtx_lock (mtx
*m
, DWORD winpid
, const char *file
, int line
)
39 _log (file
, line
, LOG_DEBUG
, "Try locking mutex %s", m
->name
);
40 if (WaitForSingleObject (m
->h
, INFINITE
) != WAIT_OBJECT_0
)
41 _panic (file
, line
, "wait for %s in %d failed, %E", m
->name
, winpid
);
43 _log (file
, line
, LOG_DEBUG
, "Locked mutex %s", m
->name
);
53 _mtx_assert (mtx
*m
, int what
, const char *file
, int line
)
59 _panic (file
, line
, "Mutex %s not owned", m
->name
);
63 _panic (file
, line
, "Mutex %s is owned", m
->name
);
71 _mtx_unlock (mtx
*m
, const char *file
, int line
)
74 /* Cautiously check if mtx_destroy has been called (shutdown).
75 In that case, m->h is NULL. */
76 if (m
->h
&& !ReleaseSemaphore (m
->h
, 1, NULL
))
78 /* Check if the semaphore was already on it's max value. In this case,
79 ReleaseSemaphore returns FALSE with an error code which *sic* depends
81 if ( (!wincap
.is_winnt () && GetLastError () != ERROR_INVALID_PARAMETER
)
82 || (wincap
.is_winnt () && GetLastError () != ERROR_TOO_MANY_POSTS
))
83 _panic (file
, line
, "release of mutex %s failed, %E", m
->name
);
85 _log (file
, line
, LOG_DEBUG
, "Unlocked mutex %s", m
->name
);
98 * Helper functions for msleep/wakeup.
101 /* Values for which */
102 #define MSLEEP_MUTEX 0
104 #define MSLEEP_EVENT 2
107 msleep_event_name (void *ident
, char *name
, int which
)
109 if (wincap
.has_terminal_services ())
110 __small_sprintf (name
, "Global\\cygserver.msleep.evt.%1d.%08x",
113 __small_sprintf (name
, "cygserver.msleep.evt.%1d.%08x", which
, ident
);
118 win_priority (int priority
)
120 int p
= (int)((priority
) & PRIO_MASK
) - PZERO
;
121 /* Generating a valid priority value is a bit tricky. The only valid
122 values on 9x and NT4 are -15, -2, -1, 0, 1, 2, 15. */
125 case -15: case -14: case -13: case -12: case -11:
126 return THREAD_PRIORITY_IDLE
;
127 case -10: case -9: case -8: case -7: case -6:
128 return THREAD_PRIORITY_LOWEST
;
129 case -5: case -4: case -3: case -2: case -1:
130 return THREAD_PRIORITY_BELOW_NORMAL
;
132 return THREAD_PRIORITY_NORMAL
;
133 case 1: case 2: case 3: case 4: case 5:
134 return THREAD_PRIORITY_ABOVE_NORMAL
;
135 case 6: case 7: case 8: case 9: case 10:
136 return THREAD_PRIORITY_HIGHEST
;
137 case 11: case 12: case 13: case 14: case 15:
138 return THREAD_PRIORITY_TIME_CRITICAL
;
140 return THREAD_PRIORITY_NORMAL
;
144 * Sets the thread priority, returns the old priority.
147 set_priority (int priority
)
149 int old_prio
= GetThreadPriority (GetCurrentThread ());
150 if (!SetThreadPriority (GetCurrentThread (), win_priority (priority
)))
152 "Warning: Setting thread priority to %d failed with error %lu\n",
153 win_priority (priority
), GetLastError ());
158 * Original description from BSD code:
160 * General sleep call. Suspends the current process until a wakeup is
161 * performed on the specified identifier. The process will then be made
162 * runnable with the specified priority. Sleeps at most timo/hz seconds
163 * (0 means no timeout). If pri includes PCATCH flag, signals are checked
164 * before and after sleeping, else signals are not checked. Returns 0 if
165 * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
166 * signal needs to be delivered, ERESTART is returned if the current system
167 * call should be restarted if possible, and EINTR is returned if the system
168 * call should be interrupted by the signal (return EINTR).
170 * The mutex argument is exited before the caller is suspended, and
171 * entered before msleep returns. If priority includes the PDROP
172 * flag the mutex is not entered before returning.
174 static HANDLE msleep_glob_evt
;
179 msleep_glob_evt
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
180 if (!msleep_glob_evt
)
181 panic ("CreateEvent in msleep_init failed: %E");
185 _msleep (void *ident
, struct mtx
*mtx
, int priority
,
186 const char *wmesg
, int timo
, struct thread
*td
)
191 /* The mutex is used to indicate an ident specific critical section.
192 The critical section is needed to synchronize access to the
193 semaphore and eventually the event object. The whole idea is
194 that a wakeup is *guaranteed* to wakeup *all* threads. If that's
195 not synchronized, sleeping threads could return into the msleep
196 function before all other threads have called CloseHandle(evt).
197 That's bad, since the event still exists and is signalled! */
198 HANDLE mutex
= CreateMutex (NULL
, FALSE
,
199 msleep_event_name (ident
, name
, MSLEEP_MUTEX
));
201 panic ("CreateMutex in msleep (%s) failed: %E", wmesg
);
202 WaitForSingleObject (mutex
, INFINITE
);
204 /* Ok, we're in the critical section now. We create an ident specific
205 semaphore, which is used to synchronize the waiting threads. */
206 HANDLE sem
= CreateSemaphore (NULL
, 0, LONG_MAX
,
207 msleep_event_name (ident
, name
, MSLEEP_SEM
));
209 panic ("CreateSemaphore in msleep (%s) failed: %E", wmesg
);
211 /* This thread is one more thread sleeping. The semaphore value is
212 so used as a counter of sleeping threads. That info is needed by
213 the wakeup function. */
214 ReleaseSemaphore (sem
, 1, NULL
);
216 /* Leave critical section. */
217 ReleaseMutex (mutex
);
219 HANDLE evt
= CreateEvent (NULL
, TRUE
, FALSE
,
220 msleep_event_name (ident
, name
, MSLEEP_EVENT
));
222 panic ("CreateEvent in msleep (%s) failed: %E", wmesg
);
225 int old_priority
= set_priority (priority
);
230 td
->client
->handle (),
231 td
->client
->signal_arrived ()
233 /* PCATCH handling. If PCATCH is given and signal_arrived is a valid
234 handle, then it's used in the WaitFor call and EINTR is returned. */
236 if ((priority
& PCATCH
)
237 && td
->client
->signal_arrived () != INVALID_HANDLE_VALUE
)
240 switch (WaitForMultipleObjects (obj_cnt
, obj
, FALSE
, timo
?: INFINITE
))
242 case WAIT_OBJECT_0
: /* wakeup() has been called. */
245 case WAIT_OBJECT_0
+ 1: /* Shutdown event (triggered by wakeup_all). */
248 case WAIT_OBJECT_0
+ 2: /* The dependent process has exited. */
251 case WAIT_OBJECT_0
+ 3: /* Signal for calling process arrived. */
258 panic ("wait in msleep (%s) failed, %E", wmesg
);
263 /* wakeup has reset the semaphore to 0. Now indicate that this thread
264 has called CloseHandle (evt) and enter the critical section. The
265 critical section is still hold by wakeup, until all formerly sleeping
266 threads have indicated that the event has been dismissed. That's
267 the signal for wakeup that it's the only thread still holding a
268 handle to the event object. wakeup will then close the last handle
269 and leave the critical section. */
270 ReleaseSemaphore (sem
, 1, NULL
);
271 WaitForSingleObject (mutex
, INFINITE
);
273 ReleaseMutex (mutex
);
276 set_priority (old_priority
);
278 if (mtx
&& !(priority
& PDROP
))
284 * Make all threads sleeping on the specified identifier runnable.
292 HANDLE evt
= OpenEvent (EVENT_MODIFY_STATE
, FALSE
,
293 msleep_event_name (ident
, name
, MSLEEP_EVENT
));
294 if (!evt
) /* No thread is waiting. */
296 /* Another round of different error codes returned by 9x and NT
297 systems. Oh boy... */
298 if ( (!wincap
.is_winnt () && GetLastError () != ERROR_INVALID_NAME
)
299 || (wincap
.is_winnt () && GetLastError () != ERROR_FILE_NOT_FOUND
))
300 panic ("OpenEvent (%s) in wakeup failed: %E", name
);
304 /* The mutex is used to indicate an ident specific critical section.
305 The critical section is needed to synchronize access to the
306 semaphore and eventually the event object. The whole idea is
307 that a wakeup is *guaranteed* to wakeup *all* threads. If that's
308 not synchronized, sleeping threads could return into the msleep
309 function before all other threads have called CloseHandle(evt).
310 That's bad, since the event still exists and is signalled! */
311 HANDLE mutex
= OpenMutex (MUTEX_ALL_ACCESS
, FALSE
,
312 msleep_event_name (ident
, name
, MSLEEP_MUTEX
));
314 panic ("OpenMutex (%s) in wakeup failed: %E", name
);
315 WaitForSingleObject (mutex
, INFINITE
);
316 /* Ok, we're in the critical section now. We create an ident specific
317 semaphore, which is used to synchronize the waiting threads. */
318 HANDLE sem
= OpenSemaphore (SEMAPHORE_ALL_ACCESS
, FALSE
,
319 msleep_event_name (ident
, name
, MSLEEP_SEM
));
321 panic ("OpenSemaphore (%s) in wakeup failed: %E", name
);
322 ReleaseSemaphore (sem
, 1, &threads
);
323 /* `threads' is the number of waiting threads. Now reset the semaphore
324 to 0 and wait for this number of threads to indicate that they have
325 called CloseHandle (evt). Then it's save to do the same here in
326 wakeup, which then means that the event object is destroyed and
327 can get safely recycled. */
328 for (int i
= threads
+ 1; i
> 0; --i
)
329 WaitForSingleObject (sem
, INFINITE
);
332 panic ("SetEvent (%s) in wakeup failed, %E", name
);
334 /* Now wait for all threads which were waiting for this wakeup. */
335 while (threads
-- > 0)
336 WaitForSingleObject (sem
, INFINITE
);
338 /* Now our handle is the last handle to this event object. */
340 /* But paranoia rulez, so we check here again. */
341 evt
= OpenEvent (EVENT_MODIFY_STATE
, FALSE
,
342 msleep_event_name (ident
, name
, MSLEEP_EVENT
));
344 panic ("Event %s has not been destroyed. Obviously I can't count :-(",
349 /* Leave critical section (all of wakeup is critical). */
350 ReleaseMutex (mutex
);
357 * Wakeup all sleeping threads. Only called in the context of cygserver
363 SetEvent (msleep_glob_evt
);
365 #endif /* __OUTSIDE_CYGWIN__ */