///////////////////////////////////////////////////////////////////////////// // Rev 06/12/2003 // // // SEMAPHORE.C // ----------- // // // Sylvain MARECHAL - sylvain.marechal1@libertysurf.fr ///////////////////////////////////////////////////////////////////////////// // // Semaphore for Win32 and unix // ///////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 #include #else #include #include #include #include #endif #include #include #include "semaphore.h" // Common definitions for unix and win32 #ifndef _WIN32 #ifndef HANDLE #define HANDLE int #endif #ifndef MAX_PATH #define MAX_PATH 1024 #endif #ifndef NULL #define NULL 0 #endif #ifndef HAVE_UNION_SEMUN union semun { int val; struct semid_ds *buf; u_short *array; } arg; #endif #endif //!_WIN32 // Internal definition of the semaphore object typedef struct _tagSemaphoreInternal { HANDLE hSem; int flags; } SemaphoreInternal; #ifdef _WIN32 ///////////////////////////////////////////////////////////////////////////// // // CREATENAMEFROMMODULEDIRECTORY ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --CreateNameFromModuleDirectory-- // // Convert a path name into a string that can be used by // Windows fonction like CreateSemaphore() or CreateFileMapping() // ARGUMENTS // Argument1: const char * pszExtention // RETOUR/RESULTAT // static char * // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// static char * CreateNameFromModuleDirectory( const char * pszExtention ) { static char s_szName[MAX_PATH]; char * pBackSlash; int i, nLen; // Get executable name s_szName[0] = 0; GetModuleFileName( GetModuleHandle(NULL), s_szName, MAX_PATH ); // keep only the directory pBackSlash = strrchr( s_szName, '\\' ); if( pBackSlash ) *pBackSlash = 0; // Add extention strcat( s_szName, pszExtention ); // Replace \\ with _ because \\ and / are often forbiden and set the name to uppercase nLen = strlen( s_szName ); for( i = 0; i < nLen; i ++ ) { if( s_szName[i] == '\\' || s_szName[i] == '/') s_szName[i] = '_'; else s_szName[i] = toupper( s_szName[i] ); } return s_szName; } #endif ///////////////////////////////////////////////////////////////////////////// // // SEMCREATE ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --semCreate-- // // Create a semaphore object // -if flag is SEM_CREAT, semaphore count is initialized to 0 // -if flag is SEM_OPEN, semaphore is opened, and call failed // if the semaphore doesn't exist // // ARGUMENTS // Argument1: const char * pszFile // Argument2: int flags // RETOUR/RESULTAT // Semaphore * // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// Semaphore * semCreate( const char * pszFile, int flags ) { SemaphoreInternal * pSem; // Alloc object pSem = (SemaphoreInternal*)calloc( 1, sizeof(SemaphoreInternal) ); if( ! pSem ) return NULL; pSem->flags = flags; #ifdef _WIN32 { if( flags & SEM_CREAT ) { // Creat semaphore and set initial count and maximum count to 1 pSem->hSem = CreateSemaphore( NULL, 1, 1, CreateNameFromModuleDirectory(pszFile) ); } if( flags & SEM_OPEN ) { // Open semaphore pSem->hSem = OpenSemaphore( SEMAPHORE_ALL_ACCESS, FALSE, CreateNameFromModuleDirectory(pszFile) ); } if( pSem->hSem ==NULL ) { semDestroy( (Semaphore*)pSem ); return NULL; } } #else /*unix*/ { key_t key = 0; // Get an unique key key = ftok(pszFile, 'S'); if( key == -1 ) { semDestroy( (Semaphore*)pSem ); return NULL; } if( flags & SEM_CREAT ) { int semval; union semun us; // Creat semaphore pSem->hSem = semget( key, 1, IPC_CREAT | 0666 ); if( pSem->hSem == -1 )//&& errno != EEXIST ) { //printf( "semget() error %d (EEXIST=%d)\n", errno, EEXIST ); semDestroy( (Semaphore*)pSem ); return NULL; } // Initialize semaphore first time us.val = 1; semval = semctl( pSem->hSem, 0, SETVAL, us ); if( semval == -1 ) { semDestroy( (Semaphore*)pSem ); return NULL; } } if( flags & SEM_OPEN ) { // Open semaphore //pSem->hSem = semget( key, 1, IPC_CREAT | 0666 | IPC_EXCL); pSem->hSem = semget( key, 1, 0666 ); if( pSem->hSem == -1 )//&& errno != EEXIST ) { //printf( "semget() error %d (EEXIST=%d)\n", errno, EEXIST ); semDestroy( (Semaphore*)pSem ); return NULL; } } } #endif return (Semaphore*)pSem; } ///////////////////////////////////////////////////////////////////////////// // // SEMACQUIRE ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --semAcquire-- // // Acquire the semaphore. If another process call semAcquire() // it will wait until first process call semRelease() or die // // ARGUMENTS // Argument1: Semaphore * pSemExternal // RETOUR/RESULTAT // int // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// int semAcquire( Semaphore * pSemExternal ) { SemaphoreInternal * pSem = (SemaphoreInternal *)pSemExternal; if( pSem == NULL ) return -1; #ifdef _WIN32 { int rWait; // Wait until semaphore is released rWait = WaitForSingleObject( pSem->hSem, INFINITE ); if( rWait == WAIT_OBJECT_0 ) { return 0; } return -1; } #else /*unix*/ { int semval; struct sembuf sops[1]; sops[0].sem_num = 0; sops[0].sem_op = -1; // SEM_UNDO is useful if process dies after semAcquire() was called // but before semRelease() call sops[0].sem_flg = SEM_UNDO; semval = semop( pSem->hSem, sops, 1 ); //printf( "semop(-1) : %d, errno=%d\n",semval,errno); return semval; } #endif } ///////////////////////////////////////////////////////////////////////////// // // SEMRELEASE ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --semRelease-- // // Release the semaphore. // // ARGUMENTS // Argument1: Semaphore * pSemExternal // RETOUR/RESULTAT // int // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// int semRelease( Semaphore * pSemExternal ) { SemaphoreInternal * pSem = (SemaphoreInternal *)pSemExternal; if( pSem == NULL ) return -1; #ifdef _WIN32 { if( ReleaseSemaphore( pSem->hSem, 1, NULL ) ) { return 0; } return -1; } #else /*unix*/ { int semval; struct sembuf sops[1]; // Release the semaphore sops[0].sem_num = 0; sops[0].sem_op = 1; // SEM_UNDO is useful if process dies after semAcquire() was called // but before semRelease() call // Note that SEM_UNDO should be call for each semop() call because // the undo is done at the end of the process, even if the process // ends normally sops[0].sem_flg = SEM_UNDO; semval = semop( pSem->hSem, sops, 1 ); //printf( "semop(1) : %d, errno=%d\n",semval,errno); return semval; } #endif } ///////////////////////////////////////////////////////////////////////////// // // SEMDESTROY ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --semDestroy-- // // Destroy the semaphore object. under unix, the system semaphore // is destroyed only for process that creat it (see semCreat(SEM_CREAT) // Otherwise, only memory if freed. // // ARGUMENTS // Argument1: Semaphore * pSemExternal // RETOUR/RESULTAT // int // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// int semDestroy( Semaphore * pSemExternal ) { SemaphoreInternal * pSem = (SemaphoreInternal *)pSemExternal; int ret = 0; if( pSem == NULL ) return -1; #ifdef _WIN32 if( pSem->hSem != NULL ) { CloseHandle(pSem->hSem); } #else if( pSem->flags & SEM_CREAT ) { if( semctl( pSem->hSem, IPC_RMID, 0, NULL ) != 0 ) { ret = -1; } } #endif free( pSem ); return ret; } ///////////////////////////////////////////////////////////////////////////// // // SEMGET ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --semGet-- // // Debbugging purpose // // ARGUMENTS // Argument1: Semaphore * pSemExternal // RETOUR/RESULTAT // int // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// int semGet( Semaphore * pSemExternal ) { SemaphoreInternal * pSem = (SemaphoreInternal *)pSemExternal; if( pSem == NULL ) return -1; #ifdef _WIN32 { return -1; // useful for unix debugging, this value is hidden under win32 } #else /*unix*/ { int semval; semval = semctl( pSem->hSem, 0, GETVAL, 0 ); if( semval == -1 ) { return -1; } return semval; } #endif } #ifdef MAIN ///////////////////////////////////////////////////////////////////////////// // // WAITKEYPRESSED ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --waitKeyPressed-- // ARGUMENTS // RETOUR/RESULTAT // static void // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// static void waitKeyPressed() { char buf[1]; printf( "Press to continue ...\n" ); read(0, buf, 1); } ///////////////////////////////////////////////////////////////////////////// // // MAIN ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --main-- // // cc -g semaphore.c -DMAIN -o semaphore // // ARGUMENTS // Argument1: int argc // Argument2: char *argv[] // RETOUR/RESULTAT // int // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv[]) { Semaphore * pSem; int ret; int flag; // Get args : no args open the semaphore if( argc != 2 ) { printf( "Usage %s <1/2>\n" "\t1=Semaphore creation\n" "\t2=Semaphore open\n", argv[0] ); flag = SEM_OPEN; } else { flag = atoi(argv[1]); } // Creat or open the semaphore pSem = semCreate( "semaphore.c", flag ); if( pSem == NULL ) { printf( "semCreate() error %d\n", errno ); exit(1); } // Print a message printf( "Prepare us to acquire the semaphore (current semval is %d)\n", semGet(pSem) ); waitKeyPressed(); // Acquire it ret = semAcquire( pSem ); if( ret < 0 ) { printf( "semAcquire() error %d\n", errno ); semDestroy( pSem ); exit(1); } // Print a message printf( "The semaphore is acquired (current semval is %d)\n", semGet(pSem) ); waitKeyPressed(); // Release it ret = semRelease( pSem ); if( ret < 0 ) { printf( "semRelease() error %d\n", errno ); semDestroy( pSem ); exit(1); } // Print a message printf( "The semaphore is released (current semval is %d)\n", semGet(pSem) ); waitKeyPressed(); // Cleanup and exit ret = semDestroy( pSem ); if( ret < 0 ) { printf( "semDestroy() error %d\n", errno ); exit(1); } return 0; } #endif