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 * Original description from BSD code:
112 * General sleep call. Suspends the current process until a wakeup is
113 * performed on the specified identifier. The process will then be made
114 * runnable with the specified priority. Sleeps at most timo/hz seconds
115 * (0 means no timeout). If pri includes PCATCH flag, signals are checked
116 * before and after sleeping, else signals are not checked. Returns 0 if
117 * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
118 * signal needs to be delivered, ERESTART is returned if the current system
119 * call should be restarted if possible, and EINTR is returned if the system
120 * call should be interrupted by the signal (return EINTR).
122 * The mutex argument is exited before the caller is suspended, and
123 * entered before msleep returns. If priority includes the PDROP
124 * flag the mutex is not entered before returning.
126 static HANDLE msleep_glob_evt;
131 msleep_glob_evt = CreateEvent (NULL, TRUE, FALSE, NULL);
132 if (!msleep_glob_evt)
133 panic ("CreateEvent in msleep_init failed: %E");
137 win_priority (int priority)
139 int p = (int)((p) & PRIO_MASK) - PZERO;
140 /* Generating a valid priority value is a bit tricky. The only valid
141 values on 9x and NT4 are -15, -2, -1, 0, 1, 2, 15. */
144 case -15: case -14: case -13: case -12: case -11:
145 return THREAD_PRIORITY_IDLE;
146 case -10: case -9: case -8: case -7: case -6:
147 return THREAD_PRIORITY_LOWEST;
148 case -5: case -4: case -3: case -2: case -1:
149 return THREAD_PRIORITY_BELOW_NORMAL;
151 return THREAD_PRIORITY_NORMAL;
152 case 1: case 2: case 3: case 4: case 5:
153 return THREAD_PRIORITY_ABOVE_NORMAL;
154 case 6: case 7: case 8: case 9: case 10:
155 return THREAD_PRIORITY_HIGHEST;
156 case 11: case 12: case 13: case 14: case 15:
157 return THREAD_PRIORITY_TIME_CRITICAL;
159 return THREAD_PRIORITY_NORMAL;
163 * Sets the thread priority, returns the old priority.
166 set_priority (int priority)
168 int old_prio = GetThreadPriority (GetCurrentThread ());
169 if (!SetThreadPriority (GetCurrentThread (), win_priority(priority)))
171 "Warning: Setting thread priority to %d failed with error %lu\n",
172 win_priority(priority), GetLastError ());
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);
191 HANDLE obj[4] = { evt, td->client->handle (), msleep_glob_evt, td->client->signal_arrived () };
192 /* PCATCH handling. If PCATCH is given and signal_arrived is a valid
193 handle, then it's used in the WaitFor call and EINTR is returned. */
195 if ((priority & PCATCH)
196 && td->client->signal_arrived () != INVALID_HANDLE_VALUE)
198 switch (WaitForMultipleObjects (obj_cnt, obj, FALSE, timo ?: INFINITE))
200 case WAIT_OBJECT_0: /* wakeup() has been called. */
203 case WAIT_OBJECT_0 + 2: /* Shutdown event (triggered by wakeup_all). */
206 case WAIT_OBJECT_0 + 1: /* The dependent process has exited. */
209 case WAIT_OBJECT_0 + 3: /* Signal for calling process arrived. */
216 panic ("wait in msleep (%s) failed, %E", wmesg);
219 set_priority (old_priority);
220 if (!(priority & PDROP) && mtx)
227 * Make all threads sleeping on the specified identifier runnable.
233 msleep_event_name (ident, name);
234 HANDLE evt = OpenEvent (EVENT_MODIFY_STATE, FALSE, name);
237 /* Another round of different error codes returned by 9x and NT
238 systems. Oh boy... */
239 if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_NAME)
240 || (wincap.is_winnt () && GetLastError () != ERROR_FILE_NOT_FOUND))
241 panic ("OpenEvent (%s) in wakeup failed: %E", name);
246 panic ("SetEvent (%s) in wakeup failed, %E", name);
253 * Wakeup all sleeping threads. Only called in the context of cygserver
259 SetEvent (msleep_glob_evt);
261 #endif /* __OUTSIDE_CYGWIN__ */