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