00001 /*! \file sem.c 00002 This file implements basic synchronosation toolkit. 00003 */ 00004 00005 #include "my_sem.h" 00006 00007 /*! \brief System identifier for the set of semaphores. */ 00008 static int semaphore_set = -1; 00009 00010 /*! \brief Number of semaphores in the set of semaphores. */ 00011 static int set_size = -1; 00012 00013 /*! \brief Default semaphores' permission used at creation time. */ 00014 static int permission = SEM_PERMISSION; 00015 00016 00017 /*! \brief Set default access permissions for the set of semaphores. 00018 \param new_permission New permissions. 00019 \warning By default, the set of semaphores is created with the persmission mask 0x000001C0, that is, in binary: 00020 111 000 000. This grants all right to the process' user but nothing for other users (just like file permissions). 00021 */ 00022 00023 void change_sem_access_permission (int new_permission) { permission = new_permission; } 00024 00025 /*! \brief Create a set of semaphores. 00026 \param ipc_key IPC key for the semaphore set. If you have a well known key (it should be a number greater or equal to 00027 zero), then you can specify it. Otherwise, if you want the kernel to find the first available key, then you must 00028 specify the value (key_t)-1. 00029 \param number_of_sem Number of semaphores in the set. 00030 \return This function may return one of the followinf values: 00031 <ul> 00032 <li>CREATE_SEMAPHORE_OK: The operation was successful. 00033 <li>CREATE_SEMAPHORE_CREATE_ERROR: A system error occured while creating the set of semaphores. 00034 <li>CREATE_SEMAPHORE_SET_VAL_ERROR: A system error occured while setting semaphores' values to 1. 00035 </ul> 00036 \warning By default, semaphores are created with the value 1 (like mutexes). You can change that later by using the 00037 function change_sem_access_permission(). 00038 */ 00039 00040 int create_semaphore_set (key_t ipc_key, int number_of_sem) 00041 { 00042 int i; 00043 union semun sem_def; 00044 00045 set_size = number_of_sem; 00046 00047 /* =============================================================== */ 00048 /* Create the set of semaphores */ 00049 /* =============================================================== */ 00050 00051 if (ipc_key != (key_t)-1) { semaphore_set = semget (ipc_key, number_of_sem, IPC_CREAT | permission); } 00052 else { semaphore_set = semget (IPC_PRIVATE, number_of_sem, IPC_CREAT | permission); } 00053 00054 if (semaphore_set == (key_t)-1) { return CREATE_SEMAPHORE_CREATE_ERROR; } 00055 00056 /* =============================================================== */ 00057 /* Set all semaphore values to 1 (can be change later) */ 00058 /* =============================================================== */ 00059 00060 for (i=0; i<number_of_sem; i++) 00061 { 00062 sem_def.val = 1; 00063 if (semctl (semaphore_set, i, SETVAL, sem_def) == -1) 00064 { return CREATE_SEMAPHORE_SET_VAL_ERROR; } 00065 } 00066 00067 return CREATE_SEMAPHORE_OK; 00068 } 00069 00070 /*! \example test_shm.c 00071 This file shows how to use the function create_semaphore_set(). 00072 */ 00073 00074 /*! \brief Get a already created (by another process) set of semaphores. 00075 \param ipc_key Well known IPC key that identifies the set of semaphores. 00076 \param number_of_sem Number of semaphores in the set. 00077 \return The function may return one of the following value: 00078 <UL> 00079 <li>GET_SEM_OK: The operation was successful. 00080 <li>GET_SEM_ALREADY_GET: The process already got the set of semaphores. 00081 <li>GET_SEM_ERROR: An error occured while getting the semaphores. 00082 </UL> 00083 \warning Since you get a semaphores set created by another process, you should know the <b>well known</b> IPC key that 00084 represents the set of semaphores. 00085 */ 00086 00087 int get_semaphore_set (key_t ipc_key, int number_of_sem) 00088 { 00089 00090 if (semaphore_set != -1) { return GET_SEM_ALREADY_GET; } 00091 00092 semaphore_set = semaphore_set = semget (ipc_key, number_of_sem, 0); 00093 set_size = number_of_sem; 00094 00095 if (semaphore_set == -1) { return GET_SEM_ERROR; } 00096 00097 return GET_SEM_OK; 00098 } 00099 00100 /*! \example test_shm.c 00101 This file shows how to use the function get_semaphore_set(). 00102 */ 00103 00104 /*! \brief Set semaphores' values (this update the entire set of semaphores). 00105 \param values Pointer to an array of integers that represents semaphores values. 00106 \return The function may return one of the followinf values: 00107 <ul> 00108 <li>SET_SEM_VALUES_OK: The operation was sucessful. 00109 <li>SET_SEM_VALUES_SEM_NOT_CREATED: You did not create (or get) the set of semaphores. 00110 <li>SET_SEM_VALUES_SET_ERROR: An error occured while setting the semaphores' values. 00111 </ul> 00112 \warning The number of elements of the array pointed by 'values' must be equal to the number of semaphores in the 00113 set. 00114 */ 00115 00116 int set_semaphore_values (int *values) 00117 { 00118 int i; 00119 union semun sem_def; 00120 00121 if ((set_size == -1) || (semaphore_set == -1)) { return SET_SEM_VALUES_SEM_NOT_CREATED; } 00122 00123 for (i=0; i<set_size; i++) 00124 { 00125 sem_def.val = values[i]; 00126 if (semctl (semaphore_set, i, SETVAL, sem_def) == -1) 00127 { return SET_SEM_VALUES_SET_ERROR; } 00128 } 00129 00130 return SET_SEM_VALUES_OK; 00131 } 00132 00133 /*! \example test_shm.c 00134 This file shows how to use the function set_semaphore_values(). 00135 */ 00136 00137 /*! \brief Set the value of one semaphore (and only one of the set). 00138 \param value Integer that represents the semaphore's new value. 00139 \sem_number Integer that represents the semaphore's index (within the set of semaphores). 00140 \return The function may return one of the followinf values: 00141 <ul> 00142 <li>SET_SEM_VALUES_OK: The operation was sucessful. 00143 <li>SET_SEM_VALUES_SEM_NOT_CREATED: You did not create (or get) the set of semaphores. 00144 <li>SET_SEM_VALUES_SET_ERROR: An error occured while setting the semaphores' values. 00145 </ul> 00146 Please note that the functions set_semaphore_value() and set_semaphore_values() share the same set of return values. 00147 */ 00148 00149 int set_semaphore_value (int value, int sem_number) 00150 { 00151 union semun sem_def; 00152 00153 if ((set_size == -1) || (semaphore_set == -1)) { return SET_SEM_VALUES_SEM_NOT_CREATED; } 00154 00155 sem_def.val = value; 00156 if (semctl (semaphore_set, sem_number, SETVAL, sem_def) == -1) 00157 { return SET_SEM_VALUES_SET_ERROR; } 00158 00159 return SET_SEM_VALUES_OK; 00160 } 00161 00162 /*! \example test_shm.c 00163 This file shows how to use the function set_semaphore_value(). 00164 */ 00165 00166 /*! \brief Take one semaphore. This action decrements the semaphore's counter by 1. 00167 \param sem_idx Index of the semaphore to take. The index of the first semaphore is 0. 00168 \return Upon successful completion, 0 is returned. Otherwise, -1 is returned. 00169 \warning If the set of semaphores you created contains N semaphores, then "0 <= sem_idx < N". 00170 */ 00171 00172 int take_sem (int sem_idx) 00173 { 00174 struct sembuf Operation; 00175 00176 Operation.sem_num = sem_idx; 00177 Operation.sem_flg = SEM_UNDO; 00178 Operation.sem_op = -1; 00179 00180 return (semop(semaphore_set, &Operation, 1)); 00181 } 00182 00183 /*! \example test_shm.c 00184 This file shows how to use the function take_sem(). 00185 */ 00186 00187 /*! \brief Release one semaphore. This action increments the semaphore's counter by 1. 00188 \param sem_idx Index of the semaphore to take. The index of the first semaphore is 0. 00189 \return Upon successful completion, 0 is returned. Otherwise, -1 is returned. 00190 \warning If the set of semaphores you created contains N semaphores, then "0 <= sem_idx < N". 00191 Please note that we do <B>NOT</B> specify the semaphore's flag <U>SEM_UNDO</U>. If you specify this flag, 00192 then you will have the following behaviour: when the program exits, the operation will be canceled. 00193 Here the operation is "release the semaphore". So, if we set SEM_UNDO, and if the process exists, 00194 then the operation will be canceled: in other words, the semaphore will be taken (the oposite of released). 00195 */ 00196 00197 int release_sem (int sem_idx) 00198 { 00199 struct sembuf Operation; 00200 00201 Operation.sem_num = sem_idx; 00202 Operation.sem_op = +1; 00203 00204 return (semop(semaphore_set, &Operation, 1)); 00205 } 00206 00207 /*! \example test_shm.c 00208 This file shows how to use the function release_sem(). 00209 */ 00210 00211 /*! \brief Destroy the set of semaphores. 00212 \return Upon successful completion, a positive value is returned. Otherwise, -1 is returned. 00213 */ 00214 00215 int destroy_semaphore_set() 00216 { return (semctl (semaphore_set, 0, IPC_RMID, 0)); } 00217 00218 /*! \example test_shm.c 00219 This file shows how to use the function destroy_semaphore_set(). 00220 */