Back to index

lightning-sunbird  0.9+nobinonly
w32ipcsem.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * File: w32ipcsem.c
00040  * Description: implements named semaphores for NT and WIN95.
00041  */
00042 
00043 #include "primpl.h"
00044 
00045 /*
00046  * NSPR-to-NT access right mapping table for semaphore objects.
00047  *
00048  * The SYNCHRONIZE access is required by WaitForSingleObject.
00049  * The SEMAPHORE_MODIFY_STATE access is required by ReleaseSemaphore.
00050  * The OR of these three access masks must equal SEMAPHORE_ALL_ACCESS.
00051  * This is because if a semaphore object with the specified name
00052  * exists, CreateSemaphore requests SEMAPHORE_ALL_ACCESS access to
00053  * the existing object.
00054  */
00055 static DWORD semAccessTable[] = {
00056     STANDARD_RIGHTS_REQUIRED|0x1, /* read (0x1 is "query state") */
00057     STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, /* write */
00058     0 /* execute */
00059 };
00060 
00061 #ifndef _PR_GLOBAL_THREADS_ONLY
00062 
00063 /*
00064  * A fiber cannot call WaitForSingleObject because that
00065  * will block the other fibers running on the same thread.
00066  * If a fiber needs to wait on a (semaphore) handle, we
00067  * create a native thread to call WaitForSingleObject and
00068  * have the fiber join the native thread.
00069  */
00070 
00071 /*
00072  * Arguments, return value, and error code for WaitForSingleObject
00073  */
00074 struct WaitSingleArg {
00075     HANDLE handle;
00076     DWORD timeout;
00077     DWORD rv;
00078     DWORD error;
00079 };
00080 
00081 static void WaitSingleThread(void *arg)
00082 {
00083     struct WaitSingleArg *warg = (struct WaitSingleArg *) arg;
00084 
00085     warg->rv = WaitForSingleObject(warg->handle, warg->timeout);
00086     if (warg->rv == WAIT_FAILED) {
00087         warg->error = GetLastError();
00088     }
00089 }
00090 
00091 static DWORD FiberSafeWaitForSingleObject(
00092     HANDLE hHandle,
00093     DWORD dwMilliseconds
00094 )
00095 {
00096     PRThread *me = _PR_MD_CURRENT_THREAD();
00097 
00098     if (_PR_IS_NATIVE_THREAD(me)) {
00099         return WaitForSingleObject(hHandle, dwMilliseconds);
00100     } else {
00101         PRThread *waitThread;
00102         struct WaitSingleArg warg;
00103         PRStatus rv;
00104 
00105         warg.handle = hHandle;
00106         warg.timeout = dwMilliseconds;
00107         waitThread = PR_CreateThread(
00108             PR_USER_THREAD, WaitSingleThread, &warg,
00109             PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
00110         if (waitThread == NULL) {
00111             return WAIT_FAILED;
00112         }
00113 
00114         rv = PR_JoinThread(waitThread);
00115         PR_ASSERT(rv == PR_SUCCESS);
00116         if (rv == PR_FAILURE) {
00117             return WAIT_FAILED;
00118         }
00119         if (warg.rv == WAIT_FAILED) {
00120             SetLastError(warg.error);
00121         }
00122         return warg.rv;
00123     }
00124 }
00125 
00126 #endif /* !_PR_GLOBAL_THREADS_ONLY */
00127 
00128 PRSem *_PR_MD_OPEN_SEMAPHORE(
00129     const char *osname, PRIntn flags, PRIntn mode, PRUintn value)
00130 {
00131     PRSem *sem;
00132     SECURITY_ATTRIBUTES sa;
00133     LPSECURITY_ATTRIBUTES lpSA = NULL;
00134     PSECURITY_DESCRIPTOR pSD = NULL;
00135     PACL pACL = NULL;
00136 
00137     sem = PR_NEW(PRSem);
00138     if (sem == NULL) {
00139         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00140         return NULL;
00141     }
00142     if (flags & PR_SEM_CREATE) {
00143         if (_PR_NT_MakeSecurityDescriptorACL(mode, semAccessTable,
00144                 &pSD, &pACL) == PR_SUCCESS) {
00145             sa.nLength = sizeof(sa);
00146             sa.lpSecurityDescriptor = pSD;
00147             sa.bInheritHandle = FALSE;
00148             lpSA = &sa;
00149         }
00150         sem->sem = CreateSemaphore(lpSA, value, 0x7fffffff, osname);
00151         if (lpSA != NULL) {
00152             _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
00153         }
00154         if (sem->sem == NULL) {
00155             _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00156             PR_DELETE(sem);
00157             return NULL;
00158         }
00159         if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) {
00160             PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS);
00161             CloseHandle(sem->sem);
00162             PR_DELETE(sem);
00163             return NULL;
00164         }
00165     } else {
00166         sem->sem = OpenSemaphore(
00167                 SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, FALSE, osname);
00168         if (sem->sem == NULL) {
00169             DWORD err = GetLastError();
00170 
00171             /*
00172              * If we open a nonexistent named semaphore, NT
00173              * returns ERROR_FILE_NOT_FOUND, while Win95
00174              * returns ERROR_INVALID_NAME
00175              */
00176             if (err == ERROR_INVALID_NAME) {
00177                 PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
00178             } else {
00179                 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00180             }
00181             PR_DELETE(sem);
00182             return NULL;
00183         }
00184     }
00185     return sem;
00186 }
00187 
00188 PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem)
00189 {
00190     DWORD rv;
00191 
00192 #ifdef _PR_GLOBAL_THREADS_ONLY
00193     rv = WaitForSingleObject(sem->sem, INFINITE);
00194 #else
00195     rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE);
00196 #endif
00197     PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0);
00198     if (rv == WAIT_FAILED) {
00199         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00200         return PR_FAILURE;
00201     }
00202     if (rv != WAIT_OBJECT_0) {
00203         /* Should not happen */
00204         PR_SetError(PR_UNKNOWN_ERROR, 0);
00205         return PR_FAILURE;
00206     }
00207     return PR_SUCCESS;
00208 }
00209 
00210 PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem)
00211 {
00212     if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) {
00213         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00214         return PR_FAILURE;
00215     }
00216     return PR_SUCCESS;
00217 }
00218 
00219 PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem)
00220 {
00221     if (CloseHandle(sem->sem) == FALSE) {
00222         _PR_MD_MAP_CLOSE_ERROR(GetLastError());
00223         return PR_FAILURE;
00224     }
00225     PR_DELETE(sem);
00226     return PR_SUCCESS;
00227 }