tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }