/* alternate.c Started by Jeff Ondich on 4/16/08 */ #include #include #include #include #include #include #include #include #define semkey_A ((key_t)5678) #define semkey_B ((key_t)5679) /* Prototypes */ char *CreateSharedMem( key_t, int ); void CreateSemaphore( key_t, int ); void Up( key_t ); void Down( key_t ); void InterruptHandler( int ); int main( void ) { pid_t pid; signal( SIGINT, InterruptHandler ); CreateSemaphore( semkey_A, 1 ); CreateSemaphore( semkey_B, 0 ); pid = fork(); if( pid == -1 ) { perror( "fork() failure" ); exit( 1 ); } if( pid != 0 ) { printf( "Process A [%d] starting\n", getpid() ); while( 1 ) { Down( semkey_A ); printf( "Hi from process A\n" ); Up( semkey_B ); } } else { printf( "Process B [%d] starting\n", getpid() ); while( 1 ) { Down( semkey_B ); printf( " Hi from process B\n" ); Up( semkey_A ); } } return( 0 ); } /*********************************************** * * CreateSharedMem * * Given a "path" and "project" (see * manual page for ftok()), create a * corresponding key, and create a "size"-byte * block of shared memory with the key. * CreateSharedMem() also attaches the shared * memory to the current process' address space, * and returns the attached address. * ***********************************************/ char *CreateSharedMem( key_t key, int size ) { int id; char *sharedMemAddr; /* Create the shared memory. */ id = shmget( key, size, 0664 | IPC_CREAT | IPC_EXCL ); if( id == -1 ) { perror( "Shmget trouble" ); InterruptHandler( 0 ); } /* Attach the shared memory to the current process' address space. */ sharedMemAddr = (char *)shmat( id, (char *)0, 0 ); if( sharedMemAddr == (char *)-1 ) { perror( "Shmat trouble" ); InterruptHandler( 0 ); } return( sharedMemAddr ); } /*********************************************** * CreateSemaphore * * Creates a single semaphore, initializes it * to "value", and returns the semaphore id. * Note that System V (and thus linux) only give * you tools for manipulating *arrays* of semaphores, * so what we're doing here is allocating an * array of one semaphore. ***********************************************/ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ }; void CreateSemaphore( key_t key, int value ) { int id; union semun arg; id = semget( key, 1, 0664 | IPC_CREAT | IPC_EXCL ); if( id == -1 ) { perror( "Couldn't create semaphore" ); InterruptHandler( 0 ); } arg.val = value; if( semctl( id, 0, SETVAL, arg ) == -1 ) { perror( "Can't set semaphore value" ); InterruptHandler( 0 ); } } /*********************************************** * Up * * Does an UP on the given semaphore. Assumes * "id" is a valid id number (obtained from semget()) * for an array of one semaphore. ***********************************************/ void Up( key_t key ) { int id; struct sembuf sops[1]; /* Operate on semaphore number 0 in the array of semaphores */ sops[0].sem_num = 0; /* Add 1 to the semaphore's value--this is what makes this an "up" */ sops[0].sem_op = 1; /* The flags IPC_NOWAIT and SEM_UNDO are not relevant for our purposes, so we make the flags 0 */ sops[0].sem_flg = 0; /* The 1 in the semop() call tells semop() how many operations are in the array "sops". We're doing one UP, and that's all. */ id = semget( key, 0, 0 ); if( id == -1 || semop( id, sops, 1 ) == -1 ) { fprintf( stderr, "[%d] ", getpid() ); perror( "Trouble doing UP" ); } } /*********************************************** * Down * * Does a DOWN on the given semaphore. Assumes * "id" is a valid id number (obtained from semget()) * for an array of one semaphore. ***********************************************/ void Down( key_t key ) { int id; struct sembuf sops[1]; /* Operate on semaphore number 0 in the array of semaphores */ sops[0].sem_num = 0; /* Add 1 to the semaphore's value--this is what makes this a "down" */ sops[0].sem_op = -1; /* The flags IPC_NOWAIT and SEM_UNDO are not relevant for our purposes, so we make the flags 0 */ sops[0].sem_flg = 0; /* The 1 in the semop() call tells semop() how many operations are in the array "sops". We're doing one DOWN, and that's all. */ id = semget( key, 0, 0 ); if( id == -1 || semop( id, sops, 1 ) == -1 ) { fprintf( stderr, "[%d] ", getpid() ); perror( "Trouble with DOWN" ); } } /*********************************************** * InterruptHandler * * Clean up IPC resources upon termination ***********************************************/ void InterruptHandler( int sig ) { int id; union semun arg; fprintf( stderr, "%d quitting\n", getpid() ); id = semget( semkey_A, 0, 0 ); semctl( id, IPC_RMID, 0, arg ); id = semget( semkey_B, 0, 0 ); semctl( id, IPC_RMID, 0, arg ); exit( 1 ); }