diff options
Diffstat (limited to 'mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c')
-rw-r--r-- | mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c b/mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c new file mode 100644 index 0000000..443cd7f --- /dev/null +++ b/mozilla/nsprpub/pr/src/md/windows/w32ipcsem.c @@ -0,0 +1,260 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: w32ipcsem.c + * Description: implements named semaphores for NT and WIN95. + */ + +#include "primpl.h" + +#ifdef WINCE +static HANDLE OpenSemaphore(DWORD inDesiredAccess, + BOOL inInheritHandle, + const char *inName) +{ + HANDLE retval = NULL; + HANDLE semaphore = NULL; + PRUnichar wideName[MAX_PATH]; /* name size is limited to MAX_PATH */ + + MultiByteToWideChar(CP_ACP, 0, inName, -1, wideName, MAX_PATH); + /* 0x7fffffff is the max count for our semaphore */ + semaphore = CreateSemaphoreW(NULL, 0, 0x7fffffff, wideName); + if (NULL != semaphore) { + DWORD lastErr = GetLastError(); + + if (ERROR_ALREADY_EXISTS != lastErr) + CloseHandle(semaphore); + else + retval = semaphore; + } + return retval; +} +#endif + +/* + * NSPR-to-NT access right mapping table for semaphore objects. + * + * The SYNCHRONIZE access is required by WaitForSingleObject. + * The SEMAPHORE_MODIFY_STATE access is required by ReleaseSemaphore. + * The OR of these three access masks must equal SEMAPHORE_ALL_ACCESS. + * This is because if a semaphore object with the specified name + * exists, CreateSemaphore requests SEMAPHORE_ALL_ACCESS access to + * the existing object. + */ +static DWORD semAccessTable[] = { + STANDARD_RIGHTS_REQUIRED|0x1, /* read (0x1 is "query state") */ + STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, /* write */ + 0 /* execute */ +}; + +#ifndef _PR_GLOBAL_THREADS_ONLY + +/* + * A fiber cannot call WaitForSingleObject because that + * will block the other fibers running on the same thread. + * If a fiber needs to wait on a (semaphore) handle, we + * create a native thread to call WaitForSingleObject and + * have the fiber join the native thread. + */ + +/* + * Arguments, return value, and error code for WaitForSingleObject + */ +struct WaitSingleArg { + HANDLE handle; + DWORD timeout; + DWORD rv; + DWORD error; +}; + +static void WaitSingleThread(void *arg) +{ + struct WaitSingleArg *warg = (struct WaitSingleArg *) arg; + + warg->rv = WaitForSingleObject(warg->handle, warg->timeout); + if (warg->rv == WAIT_FAILED) { + warg->error = GetLastError(); + } +} + +static DWORD FiberSafeWaitForSingleObject( + HANDLE hHandle, + DWORD dwMilliseconds +) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_IS_NATIVE_THREAD(me)) { + return WaitForSingleObject(hHandle, dwMilliseconds); + } else { + PRThread *waitThread; + struct WaitSingleArg warg; + PRStatus rv; + + warg.handle = hHandle; + warg.timeout = dwMilliseconds; + waitThread = PR_CreateThread( + PR_USER_THREAD, WaitSingleThread, &warg, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (waitThread == NULL) { + return WAIT_FAILED; + } + + rv = PR_JoinThread(waitThread); + PR_ASSERT(rv == PR_SUCCESS); + if (rv == PR_FAILURE) { + return WAIT_FAILED; + } + if (warg.rv == WAIT_FAILED) { + SetLastError(warg.error); + } + return warg.rv; + } +} + +#endif /* !_PR_GLOBAL_THREADS_ONLY */ + +PRSem *_PR_MD_OPEN_SEMAPHORE( + const char *osname, PRIntn flags, PRIntn mode, PRUintn value) +{ + PRSem *sem; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + sem = PR_NEW(PRSem); + if (sem == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + if (flags & PR_SEM_CREATE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, semAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } +#ifdef WINCE + { + /* The size of a sem's name is limited to MAX_PATH. */ + PRUnichar wosname[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, osname, -1, wosname, MAX_PATH); + sem->sem = CreateSemaphoreW(lpSA, value, 0x7fffffff, wosname); + } +#else + sem->sem = CreateSemaphoreA(lpSA, value, 0x7fffffff, osname); +#endif + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (sem->sem == NULL) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + PR_DELETE(sem); + return NULL; + } + if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) { + PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS); + CloseHandle(sem->sem); + PR_DELETE(sem); + return NULL; + } + } else { + sem->sem = OpenSemaphore( + SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, FALSE, osname); + if (sem->sem == NULL) { + DWORD err = GetLastError(); + + /* + * If we open a nonexistent named semaphore, NT + * returns ERROR_FILE_NOT_FOUND, while Win95 + * returns ERROR_INVALID_NAME + */ + if (err == ERROR_INVALID_NAME) { + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + } else { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + } + PR_DELETE(sem); + return NULL; + } + } + return sem; +} + +PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem) +{ + DWORD rv; + +#ifdef _PR_GLOBAL_THREADS_ONLY + rv = WaitForSingleObject(sem->sem, INFINITE); +#else + rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE); +#endif + PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0); + if (rv == WAIT_FAILED) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + if (rv != WAIT_OBJECT_0) { + /* Should not happen */ + PR_SetError(PR_UNKNOWN_ERROR, 0); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem) +{ + if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem) +{ + if (CloseHandle(sem->sem) == FALSE) { + _PR_MD_MAP_CLOSE_ERROR(GetLastError()); + return PR_FAILURE; + } + PR_DELETE(sem); + return PR_SUCCESS; +} |