Back to index

lightning-sunbird  0.9+nobinonly
mdcriticalregion.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: NULL; 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) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   George Warner, Apple Computer Inc.
00024  *   Simon Fraser  <sfraser@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "mdcriticalregion.h"
00041 #include <MacErrors.h>
00042 
00043 /*
00044   This code is a replacement for MPEnterCriticalRegion/MPLeaveCriticalRegion,
00045   which is broken on Mac OS 10.0.x builds, but fixed in 10.1. This code works
00046   everywhere.
00047 */
00048 
00049 
00050 typedef struct MDCriticalRegionData_struct {
00051   MPTaskID        mMPTaskID;          /* Who's in the critical region? */
00052   UInt32          mDepthCount;        /* How deep? */
00053   MPSemaphoreID   mMPSemaphoreID;     /* ready semaphore */
00054 } MDCriticalRegionData, *MDCriticalRegionDataPtr;
00055 
00056 
00057 OSStatus
00058 MD_CriticalRegionCreate(MDCriticalRegionID * outCriticalRegionID)
00059 {
00060   MDCriticalRegionDataPtr newCriticalRegionPtr;
00061   MPSemaphoreID           mpSemaphoreID;
00062   OSStatus                err = noErr;
00063 
00064   if (outCriticalRegionID == NULL)
00065     return paramErr;
00066 
00067   *outCriticalRegionID = NULL;
00068 
00069   newCriticalRegionPtr = (MDCriticalRegionDataPtr)MPAllocateAligned(sizeof(MDCriticalRegionData),
00070                         kMPAllocateDefaultAligned, kMPAllocateClearMask);
00071   if (newCriticalRegionPtr == NULL)
00072     return memFullErr;
00073 
00074   // Note: this semaphore is pre-fired (ready!)
00075   err = MPCreateBinarySemaphore(&mpSemaphoreID);
00076   if (err == noErr)
00077   {
00078     newCriticalRegionPtr->mMPTaskID = kInvalidID;
00079     newCriticalRegionPtr->mDepthCount = 0;
00080     newCriticalRegionPtr->mMPSemaphoreID = mpSemaphoreID;
00081 
00082     *outCriticalRegionID = (MDCriticalRegionID)newCriticalRegionPtr;
00083   }
00084   else
00085   {
00086     MPFree((LogicalAddress)newCriticalRegionPtr);
00087   }
00088 
00089   return err;
00090 }
00091 
00092 OSStatus
00093 MD_CriticalRegionDelete(MDCriticalRegionID inCriticalRegionID)
00094 {
00095   MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID;
00096   OSStatus                err = noErr;
00097 
00098   if (criticalRegion == NULL)
00099     return paramErr;
00100 
00101   if ((criticalRegion->mMPTaskID != kInvalidID) && (criticalRegion->mDepthCount > 0))
00102     return kMPInsufficientResourcesErr;
00103 
00104   if (criticalRegion->mMPSemaphoreID != kInvalidID)
00105     err = MPDeleteSemaphore(criticalRegion->mMPSemaphoreID);
00106   if (noErr != err) return err;
00107 
00108   criticalRegion->mMPSemaphoreID = kInvalidID;
00109   MPFree((LogicalAddress) criticalRegion);
00110 
00111   return noErr;
00112 }
00113 
00114 OSStatus
00115 MD_CriticalRegionEnter(MDCriticalRegionID inCriticalRegionID, Duration inTimeout)
00116 {
00117   MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID;
00118   MPTaskID                currentTaskID = MPCurrentTaskID();
00119   OSStatus                err = noErr;
00120 
00121   if (criticalRegion == NULL)
00122     return paramErr;
00123 
00124   // if I'm inside the critical region...
00125   if (currentTaskID == criticalRegion->mMPTaskID)
00126   {
00127     // bump my depth
00128     criticalRegion->mDepthCount++;
00129     // and continue
00130     return noErr;
00131   }
00132 
00133   // wait for the ready semaphore
00134   err = MPWaitOnSemaphore(criticalRegion->mMPSemaphoreID, inTimeout);
00135   // we didn't get it. return the error
00136   if (noErr != err) return err;
00137 
00138   // we got it!
00139   criticalRegion->mMPTaskID = currentTaskID;
00140   criticalRegion->mDepthCount = 1;
00141 
00142   return noErr;
00143 }
00144 
00145 OSStatus
00146 MD_CriticalRegionExit(MDCriticalRegionID inCriticalRegionID)
00147 {
00148   MDCriticalRegionDataPtr   criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID;
00149   MPTaskID                  currentTaskID = MPCurrentTaskID();
00150   OSStatus                  err = noErr;
00151 
00152   // if we don't own the critical region...
00153   if (currentTaskID != criticalRegion->mMPTaskID)
00154     return kMPInsufficientResourcesErr;
00155 
00156   // if we aren't at a depth...
00157   if (criticalRegion->mDepthCount == 0)
00158     return kMPInsufficientResourcesErr;
00159 
00160   // un-bump my depth
00161   criticalRegion->mDepthCount--;
00162 
00163   // if we just bottomed out...
00164   if (criticalRegion->mDepthCount == 0)
00165   {
00166     // release ownership of the structure
00167     criticalRegion->mMPTaskID = kInvalidID;
00168     // and signal the ready semaphore
00169     err = MPSignalSemaphore(criticalRegion->mMPSemaphoreID);
00170   }
00171   return err;
00172 }
00173