3 Copyright 2003 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>
18 #include "cygserver_ipc.h"
20 /* A BSD kernel global mutex. */
24 mtx_init (mtx *m, const char *name, const void *, int)
28 /* Can't use Windows Mutexes here since Windows Mutexes are only
29 unlockable by the lock owner. */
30 m->h = CreateSemaphore (NULL, 1, 1, NULL);
32 panic ("couldn't allocate %s mutex, %E\n", name);
36 _mtx_lock (mtx *m, DWORD winpid, const char *file, int line)
38 _log (file, line, LOG_DEBUG, "Try locking mutex %s", m->name);
39 if (WaitForSingleObject (m->h, INFINITE) != WAIT_OBJECT_0)
40 _panic (file, line, "wait for %s in %d failed, %E", m->name, winpid);
42 _log (file, line, LOG_DEBUG, "Locked mutex %s", m->name);
52 _mtx_assert(mtx *m, int what, const char *file, int line)
58 _panic(file, line, "Mutex %s not owned", m->name);
62 _panic(file, line, "Mutex %s is owned", m->name);
70 _mtx_unlock (mtx *m, const char *file, int line)
73 /* Cautiously check if mtx_destroy has been called (shutdown).
74 In that case, m->h is NULL. */
75 if (m->h && !ReleaseSemaphore (m->h, 1, NULL))
77 /* Check if the semaphore was already on it's max value. In this case,
78 ReleaseSemaphore returns FALSE with an error code which *sic* depends
80 if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_PARAMETER)
81 || (wincap.is_winnt () && GetLastError () != ERROR_TOO_MANY_POSTS))
82 _panic (file, line, "release of mutex %s failed, %E", m->name);
84 _log (file, line, LOG_DEBUG, "Unlocked mutex %s", m->name);
97 * Helper functions for msleep/wakeup.
100 msleep_event_name (void *ident, char *name)
102 if (wincap.has_terminal_services ())
103 __small_sprintf (name, "Global\\cygserver.msleep.evt.%08x", ident);
105 __small_sprintf (name, "cygserver.msleep.evt.%08x", ident);
110 win_priority (int priority)
112 int p = (int)((priority) & PRIO_MASK) - PZERO;
113 /* Generating a valid priority value is a bit tricky. The only valid
114 values on 9x and NT4 are -15, -2, -1, 0, 1, 2, 15. */
117 case -15: case -14: case -13: case -12: case -11:
118 return THREAD_PRIORITY_IDLE;
119 case -10: case -9: case -8: case -7: case -6:
120 return THREAD_PRIORITY_LOWEST;
121 case -5: case -4: case -3: case -2: case -1:
122 return THREAD_PRIORITY_BELOW_NORMAL;
124 return THREAD_PRIORITY_NORMAL;
125 case 1: case 2: case 3: case 4: case 5:
126 return THREAD_PRIORITY_ABOVE_NORMAL;
127 case 6: case 7: case 8: case 9: case 10:
128 return THREAD_PRIORITY_HIGHEST;
129 case 11: case 12: case 13: case 14: case 15:
130 return THREAD_PRIORITY_TIME_CRITICAL;
132 return THREAD_PRIORITY_NORMAL;
136 * Sets the thread priority, returns the old priority.
139 set_priority (int priority)
141 int old_prio = GetThreadPriority (GetCurrentThread ());
142 if (!SetThreadPriority (GetCurrentThread (), win_priority (priority)))
144 "Warning: Setting thread priority to %d failed with error %lu\n",
145 win_priority (priority), GetLastError ());
150 * Original description from BSD code:
152 * General sleep call. Suspends the current process until a wakeup is
153 * performed on the specified identifier. The process will then be made
154 * runnable with the specified priority. Sleeps at most timo/hz seconds
155 * (0 means no timeout). If pri includes PCATCH flag, signals are checked
156 * before and after sleeping, else signals are not checked. Returns 0 if
157 * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
158 * signal needs to be delivered, ERESTART is returned if the current system
159 * call should be restarted if possible, and EINTR is returned if the system
160 * call should be interrupted by the signal (return EINTR).
162 * The mutex argument is exited before the caller is suspended, and
163 * entered before msleep returns. If priority includes the PDROP
164 * flag the mutex is not entered before returning.
166 static HANDLE msleep_glob_evt;
171 msleep_glob_evt = CreateEvent (NULL, TRUE, FALSE, NULL);
172 if (!msleep_glob_evt)
173 panic ("CreateEvent in msleep_init failed: %E");
177 _msleep (void *ident, struct mtx *mtx, int priority,
178 const char *wmesg, int timo, struct thread *td)
182 msleep_event_name (ident, name);
183 HANDLE evt = OpenEvent (EVENT_ALL_ACCESS, FALSE, name);
185 evt = CreateEvent (NULL, TRUE, FALSE, name);
187 panic ("CreateEvent in msleep (%s) failed: %E", wmesg);
190 int old_priority = set_priority (priority);
195 td->client->handle (),
196 td->client->signal_arrived ()
198 /* PCATCH handling. If PCATCH is given and signal_arrived is a valid
199 handle, then it's used in the WaitFor call and EINTR is returned. */
201 if ((priority & PCATCH)
202 && td->client->signal_arrived () != INVALID_HANDLE_VALUE)
204 switch (WaitForMultipleObjects (obj_cnt, obj, FALSE, timo ?: INFINITE))
206 case WAIT_OBJECT_0: /* wakeup() has been called. */
209 case WAIT_OBJECT_0 + 1: /* Shutdown event (triggered by wakeup_all). */
212 case WAIT_OBJECT_0 + 2: /* The dependent process has exited. */
215 case WAIT_OBJECT_0 + 3: /* Signal for calling process arrived. */
222 panic ("wait in msleep (%s) failed, %E", wmesg);
225 set_priority (old_priority);
226 if (!(priority & PDROP) && mtx)
233 * Make all threads sleeping on the specified identifier runnable.
239 msleep_event_name (ident, name);
240 HANDLE evt = OpenEvent (EVENT_MODIFY_STATE, FALSE, name);
243 /* Another round of different error codes returned by 9x and NT
244 systems. Oh boy... */
245 if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_NAME)
246 || (wincap.is_winnt () && GetLastError () != ERROR_FILE_NOT_FOUND))
247 panic ("OpenEvent (%s) in wakeup failed: %E", name);
252 panic ("SetEvent (%s) in wakeup failed, %E", name);
259 * Wakeup all sleeping threads. Only called in the context of cygserver
265 SetEvent (msleep_glob_evt);
267 #endif /* __OUTSIDE_CYGWIN__ */