| OLD | NEW |
| (Empty) |
| 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
| 2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 5 | |
| 6 /* | |
| 7 * File: w32ipcsem.c | |
| 8 * Description: implements named semaphores for NT and WIN95. | |
| 9 */ | |
| 10 | |
| 11 #include "primpl.h" | |
| 12 | |
| 13 #ifdef WINCE | |
| 14 static HANDLE OpenSemaphore(DWORD inDesiredAccess, | |
| 15 BOOL inInheritHandle, | |
| 16 const char *inName) | |
| 17 { | |
| 18 HANDLE retval = NULL; | |
| 19 HANDLE semaphore = NULL; | |
| 20 PRUnichar wideName[MAX_PATH]; /* name size is limited to MAX_PATH */ | |
| 21 | |
| 22 MultiByteToWideChar(CP_ACP, 0, inName, -1, wideName, MAX_PATH); | |
| 23 /* 0x7fffffff is the max count for our semaphore */ | |
| 24 semaphore = CreateSemaphoreW(NULL, 0, 0x7fffffff, wideName); | |
| 25 if (NULL != semaphore) { | |
| 26 DWORD lastErr = GetLastError(); | |
| 27 | |
| 28 if (ERROR_ALREADY_EXISTS != lastErr) | |
| 29 CloseHandle(semaphore); | |
| 30 else | |
| 31 retval = semaphore; | |
| 32 } | |
| 33 return retval; | |
| 34 } | |
| 35 #endif | |
| 36 | |
| 37 /* | |
| 38 * NSPR-to-NT access right mapping table for semaphore objects. | |
| 39 * | |
| 40 * The SYNCHRONIZE access is required by WaitForSingleObject. | |
| 41 * The SEMAPHORE_MODIFY_STATE access is required by ReleaseSemaphore. | |
| 42 * The OR of these three access masks must equal SEMAPHORE_ALL_ACCESS. | |
| 43 * This is because if a semaphore object with the specified name | |
| 44 * exists, CreateSemaphore requests SEMAPHORE_ALL_ACCESS access to | |
| 45 * the existing object. | |
| 46 */ | |
| 47 static DWORD semAccessTable[] = { | |
| 48 STANDARD_RIGHTS_REQUIRED|0x1, /* read (0x1 is "query state") */ | |
| 49 STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, /* write */ | |
| 50 0 /* execute */ | |
| 51 }; | |
| 52 | |
| 53 #ifndef _PR_GLOBAL_THREADS_ONLY | |
| 54 | |
| 55 /* | |
| 56 * A fiber cannot call WaitForSingleObject because that | |
| 57 * will block the other fibers running on the same thread. | |
| 58 * If a fiber needs to wait on a (semaphore) handle, we | |
| 59 * create a native thread to call WaitForSingleObject and | |
| 60 * have the fiber join the native thread. | |
| 61 */ | |
| 62 | |
| 63 /* | |
| 64 * Arguments, return value, and error code for WaitForSingleObject | |
| 65 */ | |
| 66 struct WaitSingleArg { | |
| 67 HANDLE handle; | |
| 68 DWORD timeout; | |
| 69 DWORD rv; | |
| 70 DWORD error; | |
| 71 }; | |
| 72 | |
| 73 static void WaitSingleThread(void *arg) | |
| 74 { | |
| 75 struct WaitSingleArg *warg = (struct WaitSingleArg *) arg; | |
| 76 | |
| 77 warg->rv = WaitForSingleObject(warg->handle, warg->timeout); | |
| 78 if (warg->rv == WAIT_FAILED) { | |
| 79 warg->error = GetLastError(); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 static DWORD FiberSafeWaitForSingleObject( | |
| 84 HANDLE hHandle, | |
| 85 DWORD dwMilliseconds | |
| 86 ) | |
| 87 { | |
| 88 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 89 | |
| 90 if (_PR_IS_NATIVE_THREAD(me)) { | |
| 91 return WaitForSingleObject(hHandle, dwMilliseconds); | |
| 92 } else { | |
| 93 PRThread *waitThread; | |
| 94 struct WaitSingleArg warg; | |
| 95 PRStatus rv; | |
| 96 | |
| 97 warg.handle = hHandle; | |
| 98 warg.timeout = dwMilliseconds; | |
| 99 waitThread = PR_CreateThread( | |
| 100 PR_USER_THREAD, WaitSingleThread, &warg, | |
| 101 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); | |
| 102 if (waitThread == NULL) { | |
| 103 return WAIT_FAILED; | |
| 104 } | |
| 105 | |
| 106 rv = PR_JoinThread(waitThread); | |
| 107 PR_ASSERT(rv == PR_SUCCESS); | |
| 108 if (rv == PR_FAILURE) { | |
| 109 return WAIT_FAILED; | |
| 110 } | |
| 111 if (warg.rv == WAIT_FAILED) { | |
| 112 SetLastError(warg.error); | |
| 113 } | |
| 114 return warg.rv; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 #endif /* !_PR_GLOBAL_THREADS_ONLY */ | |
| 119 | |
| 120 PRSem *_PR_MD_OPEN_SEMAPHORE( | |
| 121 const char *osname, PRIntn flags, PRIntn mode, PRUintn value) | |
| 122 { | |
| 123 PRSem *sem; | |
| 124 SECURITY_ATTRIBUTES sa; | |
| 125 LPSECURITY_ATTRIBUTES lpSA = NULL; | |
| 126 PSECURITY_DESCRIPTOR pSD = NULL; | |
| 127 PACL pACL = NULL; | |
| 128 | |
| 129 sem = PR_NEW(PRSem); | |
| 130 if (sem == NULL) { | |
| 131 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
| 132 return NULL; | |
| 133 } | |
| 134 if (flags & PR_SEM_CREATE) { | |
| 135 if (_PR_NT_MakeSecurityDescriptorACL(mode, semAccessTable, | |
| 136 &pSD, &pACL) == PR_SUCCESS) { | |
| 137 sa.nLength = sizeof(sa); | |
| 138 sa.lpSecurityDescriptor = pSD; | |
| 139 sa.bInheritHandle = FALSE; | |
| 140 lpSA = &sa; | |
| 141 } | |
| 142 #ifdef WINCE | |
| 143 { | |
| 144 /* The size of a sem's name is limited to MAX_PATH. */ | |
| 145 PRUnichar wosname[MAX_PATH]; | |
| 146 MultiByteToWideChar(CP_ACP, 0, osname, -1, wosname, MAX_PATH); | |
| 147 sem->sem = CreateSemaphoreW(lpSA, value, 0x7fffffff, wosname); | |
| 148 } | |
| 149 #else | |
| 150 sem->sem = CreateSemaphoreA(lpSA, value, 0x7fffffff, osname); | |
| 151 #endif | |
| 152 if (lpSA != NULL) { | |
| 153 _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); | |
| 154 } | |
| 155 if (sem->sem == NULL) { | |
| 156 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 157 PR_DELETE(sem); | |
| 158 return NULL; | |
| 159 } | |
| 160 if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) { | |
| 161 PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS); | |
| 162 CloseHandle(sem->sem); | |
| 163 PR_DELETE(sem); | |
| 164 return NULL; | |
| 165 } | |
| 166 } else { | |
| 167 sem->sem = OpenSemaphore( | |
| 168 SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, FALSE, osname); | |
| 169 if (sem->sem == NULL) { | |
| 170 DWORD err = GetLastError(); | |
| 171 | |
| 172 /* | |
| 173 * If we open a nonexistent named semaphore, NT | |
| 174 * returns ERROR_FILE_NOT_FOUND, while Win95 | |
| 175 * returns ERROR_INVALID_NAME | |
| 176 */ | |
| 177 if (err == ERROR_INVALID_NAME) { | |
| 178 PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); | |
| 179 } else { | |
| 180 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 181 } | |
| 182 PR_DELETE(sem); | |
| 183 return NULL; | |
| 184 } | |
| 185 } | |
| 186 return sem; | |
| 187 } | |
| 188 | |
| 189 PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem) | |
| 190 { | |
| 191 DWORD rv; | |
| 192 | |
| 193 #ifdef _PR_GLOBAL_THREADS_ONLY | |
| 194 rv = WaitForSingleObject(sem->sem, INFINITE); | |
| 195 #else | |
| 196 rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE); | |
| 197 #endif | |
| 198 PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0); | |
| 199 if (rv == WAIT_FAILED) { | |
| 200 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 201 return PR_FAILURE; | |
| 202 } | |
| 203 if (rv != WAIT_OBJECT_0) { | |
| 204 /* Should not happen */ | |
| 205 PR_SetError(PR_UNKNOWN_ERROR, 0); | |
| 206 return PR_FAILURE; | |
| 207 } | |
| 208 return PR_SUCCESS; | |
| 209 } | |
| 210 | |
| 211 PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem) | |
| 212 { | |
| 213 if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) { | |
| 214 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 215 return PR_FAILURE; | |
| 216 } | |
| 217 return PR_SUCCESS; | |
| 218 } | |
| 219 | |
| 220 PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem) | |
| 221 { | |
| 222 if (CloseHandle(sem->sem) == FALSE) { | |
| 223 _PR_MD_MAP_CLOSE_ERROR(GetLastError()); | |
| 224 return PR_FAILURE; | |
| 225 } | |
| 226 PR_DELETE(sem); | |
| 227 return PR_SUCCESS; | |
| 228 } | |
| OLD | NEW |