/* ====================================================================== */ /* Please remember that you should define the build target (could be */ /* SUN or LINUX). This is required for the semaphore/SHM library. */ /* This program works as a Productor/Consumer test. Example of use: */ /* */ /* $ ./shm.test 50 1024 create 6 & */ /* This command line create a "productor". This process will perform */ /* the following actions: */ /* (a) Create a shared memory segment. */ /* (b) Create a set of 3 semaphores. */ /* (c) Wait for a "consumer" to appear (this is done by taking a sema- */ /* -phore that will be incremented by the "consumer"). */ /* */ /* $ ./shm.test 50 1024 get 6 & */ /* This command line will create a "consumer". This process will awake */ /* the (waiting) "productor". The "consumer" will perform the following */ /* actions: */ /* (a) Get and attach the shared memory segment. */ /* (b) Get the set of semaphores. */ /* */ /* Then the "consumer" xill read - and print - data produced by the */ /* "productor". */ /* ====================================================================== */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include "my_shm.h" #include "my_sem.h" #define NO_ACTION -1 #define CREATE_SHM 0 #define GET_SHM 1 #define NUMBER_OF_SEM 3 /* number of semaphores */ #define ELEMENT 0 /* semaphore */ #define SPACE 1 /* semaphore */ #define START 2 /* semaphore */ int main (int argc, char *argv[]) { int ipc_key, shm_size, action, cr, sem_number, sem_values[NUMBER_OF_SEM], data, max_data; /* ==================================================================== */ /* Check the command line arguments */ /* ==================================================================== */ if (argc != 5) { fprintf (stderr, "\nUsage: shm.test <IPC key (shm and sem)> <SHM size> <action> <max data>"); fprintf (stderr, "\n -- if 'IPC key' is equal to -1, then the system choose the IPC keys"); fprintf (stderr, "\n -- 'action' could be 'create' or 'get'"); fprintf (stderr, "\n"); return 1; } ipc_key = atoi(argv[1]); shm_size = atoi(argv[2]); sem_number = NUMBER_OF_SEM; max_data = atoi(argv[4]); action = NO_ACTION; if (strcmp(argv[3], "create") == 0) { action = CREATE_SHM; } if (strcmp(argv[3], "get") == 0) { action = GET_SHM; } if (action == NO_ACTION) { fprintf (stderr, "\nInvalid action (must be 'create' or 'get')\n"); return 1; } /* ==================================================================== */ /* Create or get (if already created) the SHM */ /* Create or get (if already created) the semaphores */ /* ==================================================================== */ switch (action) { case CREATE_SHM: { /* ========================================================== */ /* Create the Shared Memory Segment */ /* ========================================================== */ fprintf (stdout, "\nProductor: Create Shared Memory Segment\n"); fflush (stdout); cr = create_shared_memory_segment ((key_t)ipc_key, shm_size); switch (cr) { case CREATE_SHM_ALREADY_CREATED: fprintf (stderr, "\nCan not create SHM: already created\n"); return 1; case CREATE_SHM_ERROR: fprintf (stderr, "\nCan not create SHM: system error - %s\n", strerror(errno)); return 1; } /* ========================================================== */ /* Create the set of semaphores */ /* ========================================================== */ fprintf (stdout, "\nProductor: Create set of semaphores\n"); fflush (stdout); cr = create_semaphore_set ((key_t)ipc_key+1, sem_number); switch (cr) { case CREATE_SEMAPHORE_CREATE_ERROR: fprintf (stderr, "\nCan not create SEM - %s\n", strerror(errno)); return 1; case CREATE_SEMAPHORE_SET_VAL_ERROR: fprintf (stderr, "\nCan not set SEM values - %s\n", strerror(errno)); return 1; } }; break; case GET_SHM: { /* ========================================================== */ /* Get the Shared Memory Segment */ /* ========================================================== */ fprintf (stdout, "\nConsumer: Get Shared Memory Segment\n"); fflush (stdout); cr = get_shared_memory_segment_sys_id ((key_t)ipc_key, shm_size); switch (cr) { case GET_SHM_ALREADY_GET: fprintf (stderr, "\nCan not get SHM's id: already get\n"); return 1; case GET_SHM_ERROR: fprintf (stderr, "\nCan not get SHM's id: system error - %s\n", strerror(errno)); return 1; } /* ========================================================== */ /* Get the set of semaphores */ /* ========================================================== */ fprintf (stdout, "\nConsumer: Get set of semaphores\n"); fflush (stdout); cr = get_semaphore_set ((key_t)ipc_key+1, 2); switch (cr) { case GET_SEM_ALREADY_GET: fprintf (stderr, "\nCan not get SEM - The process already got the semaphores\n"); return 1; case GET_SEM_ERROR: fprintf (stderr, "\nError while getting set of semaphores - %d - %s\n", errno, strerror(errno)); return 1; } }; break; } /* ==================================================================== */ /* Once created, the SHM must be attached to the process */ /* ==================================================================== */ if (attache_shared_memory_segment() == (SHM_addr)-1) { fprintf (stderr, "\nError while attaching the SHM - %s\n", strerror(errno)); return 1; } /* ==================================================================== */ /* Print information */ /* ==================================================================== */ fprintf (stdout, "\n"); fprintf (stdout, "\nProcess ID is: %d", (int)getpid()); fprintf (stdout, "\nSHM system ID is: %d", get_shared_memory_segment_id()); fprintf (stdout, "\nSHM bind address is: %0X", (unsigned int)attache_shared_memory_segment()); fprintf (stdout, "\nAttachemant number is: %d", (int)(get_shm_info()->shm_nattch)); fprintf (stdout, "\n"); /* ==================================================================== */ /* Set all shared memory segment to zero */ /* ==================================================================== */ memset ((void*)get_shm_address(), 0, shm_size); /* ==================================================================== */ /* Implement a basic productor / consumer protocol */ /* ==================================================================== */ /* ================================================================== */ /* We need to synchronize the productor and the consumer ... */ /* ================================================================== */ if (action == CREATE_SHM) { fprintf (stdout, "\nProductor: Set ELEMENT value to 0"); fprintf (stdout, "\nProductor: Set SPACE value to 1"); fprintf (stdout, "\nProductor: Set START value to 0 and take it => I should go to sleep"); fflush (stdout); sem_values[ELEMENT] = 0; sem_values[SPACE] = 1; sem_values[START] = 0; cr = set_semaphore_values (sem_values); switch(cr) { case SET_SEM_VALUES_SEM_NOT_CREATED: fprintf (stderr, "\nProductor: Error while setting semaphores' values - Semaphores not created\n"); return 1; case SET_SEM_VALUES_SET_ERROR: fprintf (stderr, "\nProductor: Error while setting semaphores' values - %s\n", strerror(errno)); return 1; } if (take_sem(START) == -1) { fprintf (stderr, "\nProductor: Error while tacking START - %s\n", strerror(errno)); return 1; } fprintf (stdout, "\nProductor (%d): I have START!", (int)getpid()); fflush (stdout); } /****/ if (action == GET_SHM) { fprintf (stdout, "\nConsumer: Set START to 1, this should awake the productor ...\n"); fflush (stdout); cr = set_semaphore_value (1, START); switch(cr) { case SET_SEM_VALUES_SEM_NOT_CREATED: fprintf (stderr, "\nConsumer: Error while setting START to 1 - Semaphores not get\n"); return 1; case SET_SEM_VALUES_SET_ERROR: fprintf (stderr, "\nConsumer: Error while setting START to 1 - %s\n", strerror(errno)); return 1; } } /* ================================================================== */ /* OK, now the productor is running with the consumer */ /* -> The productor gets ELEMENT. */ /* -> The consumer gets SPACE. */ /* */ /* The situation is clear ... lets proceed */ /* ================================================================== */ data = 0; while(data != -1) { /* ================================================================ */ /* PRODUCTOR */ /* ================================================================ */ if (action == CREATE_SHM) { if (take_sem(SPACE) == -1) { fprintf (stderr, "\nProductor: Error while tacking PLACE - %s\n", strerror(errno)); return 1; } if (data > max_data) { data = -1; } memcpy ((void*)get_shm_address(), (void*)&data, sizeof(int)); sleep (1); if (release_sem(ELEMENT) == -1) { fprintf (stderr, "\nProductor: Error while releasing ELEMENT - %s\n", strerror(errno)); return 1; } fprintf (stdout, "\nProductor: %d", data); fflush(stdout); if (data != -1) { data++; } } /* ================================================================ */ /* CONSUMER */ /* ================================================================ */ if (action == GET_SHM) { if (take_sem(ELEMENT) == -1) { fprintf (stderr, "\nConsumer: Error while getting ELEMENT - %s\n", strerror(errno)); return 1; } memcpy ((void*)&data, (void*)get_shm_address(), sizeof(int)); if (release_sem(SPACE) == -1) { fprintf (stderr, "\nConsumer: Error while releasing PLACE - %s\n", strerror(errno)); return 1; } fprintf (stdout, "\nConsumer: %d", data); fflush(stdout); } } /* ==================================================================== */ /* return */ /* ==================================================================== */ if (action == CREATE_SHM) { fprintf (stdout, "\nProductor: exit now\n\n"); if (set_shm_auto_destroy() == -1) { fprintf (stderr, "\nProductor: Error while setting SHM into auto-destry mode - %s\n", strerror(errno)); return 1; } if (detache_shm() == -1) { fprintf (stderr, "\nProductor: Error while detaching SHM - %s\n", strerror(errno)); return 1; } if (release_sem(START) == -1) { fprintf (stderr, "\nProductor: Error while releasing START - %s\n", strerror(errno)); return 1; } return 0; } /* ==================================================================== */ /* The consumer waits for the productor to terminate */ /* ==================================================================== */ if (action == GET_SHM) { if (take_sem(START) == -1) { fprintf (stderr, "\nConsumer: Error while tacking START - %s\n", strerror(errno)); return 1; } if (destroy_semaphore_set() == -1) { fprintf (stderr, "\nConsumer: Error while destroying the set of semaphores - %s\n", strerror(errno)); return 1; } if (detache_shm() == -1) { fprintf (stderr, "\nConsumer: Error while detaching SHM - %s\n", strerror(errno)); return 1; } } return 0; }