///////////////////////////////////////////////////////////////////////////// // Rev 06/12/2003 // // // MEMSHARE.C // ---------- // // // Sylvain MARECHAL - sylvain.marechal1@libertysurf.fr ///////////////////////////////////////////////////////////////////////////// // // Shared memory and semaphores for Win32 and unix // Some part of code are duplicated to simplify tests // // TO DO : // -Use semaphore.c /.h to avoid duplication of code // -CreateNameFromModuleDirectory() should be in a separate file // to avoid duplication // ///////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 #include #include #define sleep(a) Sleep(1000*(a)) #else #include #include #include #include #endif #include #include #include "memshare.h" #ifndef _WIN32 #ifndef DWORD #define DWORD unsigned int #endif #ifndef BOOL #define BOOL int #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef HANDLE #define HANDLE int #endif #endif // Main structure typedef struct _tagMemShareInternal { HANDLE hmap; HANDLE hsem; void * lpvmem; DWORD dwSize; BOOL fAlreadyExist; } MemShareInternal; // Test program #define MAIN #ifdef MAIN int main( int argc, char * argv[] ) { MemShare * ptMemShare; char * pData; ptMemShare = MemShCreate( "./memshare.c", 256 ); // acquire semaphore printf( "Before MemShBeginCritical()\n" ); while( MemShBeginCritical( ptMemShare ) != 0 ) { printf( "Waiting for semaphore\n" ); sleep(1); } printf( "After MemShBeginCritical()\n" ); // Retrieve data pointer pData = (char *)MemShGetPointer( ptMemShare ); // Argc == 1 => write data in shared memory if( argc == 1 ) { // Write something char test[] = "coucou"; memcpy( pData, test, sizeof(test) ); printf( "Wait 10 seconds ...\n" ); sleep(10); } else { // Read data and print it printf( "pData='%s'\n", pData ); } // Release semaphore MemShEndCritical( ptMemShare ); // release resources MemShDestroy( ptMemShare ); #ifdef _WIN32 printf( "Press a key...\n" ); getch(); #endif printf( "Exiting ...\n" ); } #endif #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 ///////////////////////////////////////////////////////////////////////////// // // MEMSHCREATE ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --MemShCreate-- // ARGUMENTS // Argument1: const char * pszFile // Argument2: DWORD dwSize // RETOUR/RESULTAT // MemShare * // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// MemShare * MemShCreate( const char * pszFile, DWORD dwSize ) { MemShareInternal * ptMemShare; #ifdef _WIN32 char szName[MAX_PATH]; #else int semval; struct sembuf sops[1]; BOOL fFirstTime; key_t key = 0; #endif ptMemShare = (MemShareInternal *)calloc( 1, sizeof(MemShareInternal) ); if( ! ptMemShare ) return ptMemShare; #ifdef _WIN32 // Create shared memory of size dwSize ptMemShare->dwSize = dwSize; sprintf( szName, "FILEMAP%s", CreateNameFromModuleDirectory(pszFile) ); ptMemShare->hmap = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, dwSize, szName ); if( ptMemShare->hmap == NULL ) { MemShDestroy( ptMemShare ); return NULL; } if( GetLastError() == ERROR_ALREADY_EXISTS ) { ptMemShare->fAlreadyExist = TRUE; } else { ptMemShare->fAlreadyExist = FALSE; } // Map it into memory ptMemShare->lpvmem = MapViewOfFile( ptMemShare->hmap, FILE_MAP_WRITE, 0, 0, 0 ); if( ptMemShare->lpvmem == NULL ) { MemShDestroy( ptMemShare ); return NULL; } // Create a semaphore sprintf( szName, "SEM%s", CreateNameFromModuleDirectory(pszFile) ); ptMemShare->hsem = CreateSemaphore( NULL, 1, 1, szName ); if( ptMemShare->hsem ==NULL ) { MemShDestroy( ptMemShare ); return NULL; } return ptMemShare; #else /*unix*/ // Get an unique key key = ftok(pszFile, 'S'); if( key == -1 ) { semDestroy( (Semaphore*)pSem ); return NULL; } // First create share mem ptMemShare->dwSize = dwSize; // try to open it ptMemShare->fAlreadyExist = TRUE; fFirstTime = FALSE; ptMemShare->hmap = shmget( key, ptMemShare->dwSize, 0666 ); if( errno == ENOENT ) { // Doesn't exist => creat it ptMemShare->fAlreadyExist = FALSE; fFirstTime = TRUE; ptMemShare->hmap = shmget( key, ptMemShare->dwSize, IPC_CREAT | 0666 ); if( ptMemShare->hmap < 0 ) { MemShDestroy( ptMemShare ); return NULL; } } // Attach memory segment ptMemShare->lpvmem = shmat( ptMemShare->hmap, (char *)0, 0); if( ptMemShare->lpvmem == -1 ) { MemShDestroy( ptMemShare ); return NULL; } // Create semaphore ptMemShare->hsem = semget( key, 1, IPC_CREAT | 0666 | IPC_EXCL); if( ptMemShare->hsem == -1 && errno != EEXIST ) { MemShDestroy( ptMemShare ); return NULL; } if( errno == EEXIST ) { ptMemShare->hsem = semget( key, 1, IPC_CREAT | 0666 ); if( ptMemShare->hsem == -1 && errno != EEXIST ) { MemShDestroy( ptMemShare ); return NULL; } } // Init semaphore first time only if( fFirstTime ) { semval=semctl(ptMemShare->hsem, 0, SETVAL, 1 ); if( semval == -1 ) { MemShDestroy( ptMemShare ); return NULL; } } #endif return (MemShare * )ptMemShare; } ///////////////////////////////////////////////////////////////////////////// // // MEMSHDESTROY ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --MemShDestroy-- // // Close all opened object and free memory // // ARGUMENTS // Argument1: MemShare * ptvMemShare // RETOUR/RESULTAT // void // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// void MemShDestroy( MemShare * ptvMemShare ) { MemShareInternal * ptMemShare = (MemShareInternal * )ptvMemShare; if( ! ptMemShare ) return; #ifdef _WIN32 if( ptMemShare->lpvmem != NULL ) UnmapViewOfFile( ptMemShare->lpvmem ); if( ptMemShare->hmap != NULL ) CloseHandle(ptMemShare->hmap); if( ptMemShare->hsem != NULL ) CloseHandle(ptMemShare->hsem); #else /*unix*/ if( shmdt( ptMemShare->lpvmem ) < 0 ) { //printf( "MemShareDestroy() : shmdt( ptMemShare->lpvmem ) < 0 (%d)\n", errno ) ; } if( ! ptMemShare->fAlreadyExist ) { if( shmctl( ptMemShare->hmap, IPC_RMID, (struct shmid_ds *)0 ) < 0 ) { printf( "MemShareDestroy() : shmctl( shmid, IPC_RMID, (struct shmid_ds *)0 ) < 0 (%d)\n", errno ); } if( semctl( ptMemShare->hsem, IPC_RMID, NULL, NULL ) != 0 ) { printf( "MemShareDestroy() : semctl( ptMemShare->hsem, IPC_RMID, NULL, NULL ) != 0 (%d)\n", errno ); } } #endif free( ptMemShare ); } ///////////////////////////////////////////////////////////////////////////// // // MEMSHBEGINCRITICAL ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --MemShBeginCritical-- // // Try to acquire semaphore - return -1 (DON'T WAIT) if it isn't possible yet // // ARGUMENTS // Argument1: MemShare * ptvMemShare // RETOUR/RESULTAT // int 0 ok, -1 ko // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// BOOL MemShBeginCritical( MemShare * ptvMemShare ) { MemShareInternal * ptMemShare = (MemShareInternal * )ptvMemShare; #ifdef _WIN32 int rWait; // Test semaphore rWait = WaitForSingleObject( ptMemShare->hsem, 0 ); if( rWait == WAIT_OBJECT_0 ) { return 0; } else if( rWait == WAIT_FAILED ) { //printf( "MemShBeginCritical() : WaitForSingleObject() == WAIT_FAILED (%d)\n", errno ); } return -1; #else /*unix*/ int semval; struct sembuf sops[1]; sops[0].sem_num = 0; sops[0].sem_op = -1; sops[0].sem_flg = IPC_NOWAIT; semval = semop(ptMemShare->hsem, sops, 1 ); if( semval == 0 ) { return 0; } if( semval == -1 && errno == EAGAIN ) { return -1; } //printf( "MemShBeginCritical() : semop( -1 ) == -1 (%d)\n", errno ); return -1; #endif } ///////////////////////////////////////////////////////////////////////////// // // MEMSHENDCRITICAL ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --MemShEndCritical-- // // Relese semaphore // // ARGUMENTS // Argument1: MemShare * ptvMemShare // RETOUR/RESULTAT // BOOL // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// BOOL MemShEndCritical( MemShare * ptvMemShare ) { MemShareInternal * ptMemShare = (MemShareInternal * )ptvMemShare; /* On indique que la memoire est libre d'acces */ #ifdef _WIN32 return ( ReleaseSemaphore( ptMemShare->hsem, 1, NULL ) ? 0 : -1 ); #else /*unix*/ int semval; struct sembuf sops[1]; /* On peut deverrouiller la semaphore */ sops[0].sem_num = 0; sops[0].sem_op = 1; sops[0].sem_flg = 0; semval = semop(ptMemShare->hsem, sops, 1 ); /*printf( "MemShEndCritical : Resultat de semop(-1) : %d, errno=%d\n",semval,errno);*/ if( semval == -1 ) { //printf( "MemShEndCritical() : semop( 1 ) == -1 (%d)\n", errno ); return -1; } return 0; #endif } ///////////////////////////////////////////////////////////////////////////// // // MEMSHGETPOINTER ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --MemShGetPointer-- // // Get the shared memory pointer // // ARGUMENTS // Argument1: MemShare * ptvMemShare // RETOUR/RESULTAT // void * // REMARQUE // Rev 06/12/2003 ////////////////////////////////////////////////////////////////////////////// void * MemShGetPointer( MemShare * ptvMemShare ) { MemShareInternal * ptMemShare = (MemShareInternal * )ptvMemShare; return ptMemShare->lpvmem; }