//+---------------------------------------------------------------------------- // // File: semaphore.cpp // // Module: // // Synopsis: // // Copyright (C) 1999 Microsoft Corporation. All rights reserved. // // Author: sgasch // // Created 8 Jun 1999 // //+---------------------------------------------------------------------------- #include "lock.h" //+---------------------------------------------------------------------------- // // Function: CCriticalSection // // Synopsis: Constructor for a "critical section" mutual exclusion device. // It basically just creates a private semaphore. It also sets // an initialized flag on success. // // Arguments: int iNum - the number of concurrent threads allowed into the // critical section. // // Returns: none // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- CCriticalSection::CCriticalSection(int iNum) { #ifdef SHOWCALLS Trace("Entering CCriticalSection constructor."); #endif // // Precondition: the number of concurrent threads is sane. // ASSERT(iNum > 0); ASSERT(iNum < 128); // // Initialize attributes. // m_fInitialized = false; m_hSem = -1; // // Create the semaphore. // if (false == CreateSemaphore()) { Trace("CCriticalSection: failed to create a semaphore."); return; } ASSERT(m_hSem != -1); // // Set the number of concurrent threads allowed into the semaphore. // if (false == SetNumConcurrentThreads(iNum)) { return; } // // Success // m_fInitialized = true; } //+---------------------------------------------------------------------------- // // Function: CCriticalSection // // Synopsis: Destructor; delete the critical section. // // Arguments: void // // Returns: none // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- CCriticalSection::~CCriticalSection(void) { #ifdef SHOWCALLS Trace("Entering ~CSemaphore destructor."); #endif // // Delete the semaphore. // if (m_hSem >= 0) { (void) RemoveSemaphore(); } m_fInitialized = false; m_hSem = -1; } //+---------------------------------------------------------------------------- // // Function: CreateSemaphore // // Synopsis: Called by the constructor to create a private semaphore. // // Arguments: void // // Returns: bool - true on success // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- bool CCriticalSection::CreateSemaphore(void) { union semun uSun; // required by the system call #ifdef SHOWCALLS Trace("Entering CreateSemaphore."); #endif // // No preconditions: we do _not_ assert initialized because we are // called by the constructor before fully inited. // // // Create the semaphore // m_hSem = semget(IPC_PRIVATE, 1, IPC_CREAT | SEM_R | (SEM_R >> 3) | SEM_A | (SEM_A >> 3)); if (m_hSem < 0) { Trace("CreateSemaphore: error creating semaphore."); return(false); } // // Initialize the semaphore. // uSun.val = 1; if (semctl(m_hSem, 0, SETVAL, uSun) < 0) { Trace("CreateSemaphore: error setting semaphore value."); return(false); } // // Success // return(true); } //+---------------------------------------------------------------------------- // // Function: RemoveSemaphore // // Synopsis: Delete a semaphore created by CreateSemaphore. // // Arguments: void // // Returns: bool - true on success. // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- bool CCriticalSection::RemoveSemaphore(void) { union semun uSun; // required by the system call #ifdef SHOWCALLS Trace("Entering RemoveSemaphore."); #endif // // Preconditions: we are initialized. // ASSERT(m_fInitialized); // // Remove the semaphore // uSun.val = 0; if (semctl(m_hSem, 0, IPC_RMID, uSun) < 0) { Trace("RemoveSemaphore: error removing semaphore."); return(false); } // // Success // return(true); } //+---------------------------------------------------------------------------- // // Function: GetNumberConcurrentThreads // // Synopsis: Return the number of concurrent threads allowed into the // critical section. // // Arguments: int *piAnswer - location to place the answer // // Returns: bool - true on success // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- bool CCriticalSection::GetNumberConcurrentThreads(int *piAnswer) { int iSemVal; // Temp local storage for the answer union semun uSun; // required by the system call #ifdef SHOWCALLS Trace("Entering GetNumberConcurrentThreads."); #endif // // Preconditions: we are initialized and the pointer is valid. // ASSERT(m_fInitialized); ASSERT(GOOD_PTR(piAnswer)); // // Get the value of the semaphore // uSun.val = 0; iSemVal = semctl(m_hSem, 0, GETVAL, uSun); if (iSemVal < 0) { Trace("GetValue: error reading semaphore value."); return(false); } else { *piAnswer = iSemVal; return(true); } } //+---------------------------------------------------------------------------- // // Function: SetNumberConcurrentThreads // // Synopsis: Set the number of concurrent threads allowed into the critical // section. // // Arguments: int iValue - number to set to // // Returns: bool - true on success // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- bool CCriticalSection::SetNumberConcurrentThreads(int iValue) { union semun uSun; // required by the system call #ifdef SHOWCALLS Trace("Entering SetNumberConcurrentThreads."); #endif // // Precondition: the value is valid. We do _not_ assert initialized // here because we get called by the constructor before fully inited. // ASSERT(iValue > 0); ASSERT(iValue < 128); // // Set the value of the semaphore // uSun.val = iValue; if (semctl(m_hSem, 0, SETVAL, uSun) < 0) { Trace("SetValue: error writing semaphore value."); return(false); } // // Success // return(true); } //+---------------------------------------------------------------------------- // // Function: TryToEnter // // Synopsis: Attempt to enter the critical section; if the call to enter // would cause the thread to block waiting for another to leave // then simply return false. If the call to enter succeeds, ret- // urn true. // // Arguments: void // // Returns: bool - true on successful enter, false on failure. // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- bool CCriticalSection::TryToEnter(void) { static struct sembuf sb[1]; // required by the system call int iError; // result of trying to enter C.S. #ifdef SHOWCALLS Trace("Entering TryToEnter."); #endif // // Preconditions: we are initialized. // ASSERT(m_fInitialized); sb[0].sem_op = -1; sb[0].sem_num = 0; sb[0].sem_flg = IPC_NOWAIT; if ((iError = semop(m_hSem, &sb[0], 1)) < 0) { if (EAGAIN == iError) { Trace("TryToEnter: could not enter critical section."); return(false); } else { Trace("TryToEnter: error waiting on semaphore."); return(false); } } Trace("TryToEnter: entered critical section successfully."); return(true); } //+---------------------------------------------------------------------------- // // Function: Enter // // Synopsis: Enter the critical section. If we cannot, sleep until we // can. // // Arguments: void // // Returns: bool - true on success // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- bool CCriticalSection::Enter(void) { static struct sembuf sb[1]; // required by the system call #ifdef SHOWCALLS Trace("Enter: beginning to wait on a critical section."); #endif // // Precondition: we are initialized. // ASSERT(m_fInitialized); // // Wait on the semaphore. // sb[0].sem_op = -1; sb[0].sem_num = 0; sb[0].sem_flg = 0; if (semop(m_hSem, &sb[0], 1) < 0) { Trace("Enter: error waiting on semaphore."); return(false); } // // Success // #ifdef SHOWCALLS Trace("Enter: entered critical section."); #endif return(true); } //+---------------------------------------------------------------------------- // // Function: Leave // // Synopsis: Leave a critical section. Make room for other(s) waiting if // they exist. // // Arguments: void // // Returns: bool - true on success // // History: sgasch Created Header 9 Jun 1999 // //+---------------------------------------------------------------------------- bool CCriticalSection::Leave(void) { static struct sembuf sb[1]; // required by the system call #ifdef SHOWCALLS Trace("Entering Leave."); #endif // // Signal the semaphore. // sb[0].sem_op = 1; sb[0].sem_num = 0; sb[0].sem_flg = 0; if (semop(m_hSem, &sb[0], 1) < 0) { Trace("Leave: error signaling semaphore."); return(false); } // // Success // return(true); }