1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1985-2012 AT&T Intellectual Property * 5* and is licensed under the * 6* Eclipse Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.eclipse.org/org/documents/epl-v10.html * 11* (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12* * 13* Information and Software Systems Research * 14* AT&T Research * 15* Florham Park NJ * 16* * 17* Glenn Fowler <gsf@research.att.com> * 18* David Korn <dgk@research.att.com> * 19* Phong Vo <kpv@research.att.com> * 20* * 21***********************************************************************/ 22#pragma prototyped 23 24#include "asohdr.h" 25 26#if defined(_UWIN) && defined(_BLD_ast) || !_aso_semaphore 27 28NoN(aso_meth_semaphore) 29 30#else 31 32#include <sys/stat.h> 33#include <sys/ipc.h> 34#include <sys/sem.h> 35 36#define SPIN 1000000 37 38typedef union Semun_u 39{ 40 int val; 41 struct semid_ds* ds; 42 unsigned short* array; 43} Semun_t; 44 45typedef struct APL_s 46{ 47 int id; 48 size_t size; 49} APL_t; 50 51static void* 52aso_init_semaphore(void* data, const char* details) 53{ 54 APL_t* apl = (APL_t*)data; 55 char* path; 56 char* opt; 57 size_t size; 58 size_t n; 59 int key; 60 int id; 61 int perm; 62 struct sembuf sem; 63 char tmp[64]; 64 65 if (apl) 66 { 67 /* 68 * semaphore 0 is the reference count 69 * the id is dropped on last reference 70 */ 71 72 sem.sem_num = 0; 73 sem.sem_op = -1; 74 sem.sem_flg = IPC_NOWAIT; 75 semop(apl->id, &sem, 1); 76 sem.sem_op = 0; 77 if (!semop(apl->id, &sem, 1)) 78 semctl(apl->id, 0, IPC_RMID); 79 free(apl); 80 return 0; 81 } 82 perm = S_IRUSR|S_IWUSR; 83 size = 128; 84 if (path = (char*)details) 85 while (opt = strchr(path, ',')) 86 { 87 if (strneq(path, "perm=", 5)) 88 { 89 if ((n = opt - (path + 5)) >= sizeof(tmp)) 90 n = sizeof(tmp) - 1; 91 memcpy(tmp, path + 5, n); 92 tmp[n] = 0; 93 perm = strperm(tmp, NiL, perm); 94 } 95 else if (strneq(path, "size=", 5)) 96 { 97 size = strtoul(path + 5, NiL, 0); 98 if (size <= 1) 99 return 0; 100 } 101 path = opt + 1; 102 } 103 key = (!path || !*path || streq(path, "private")) ? IPC_PRIVATE : (strsum(path, 0) & 0x7fff); 104 for (;;) 105 { 106 if ((id = semget(key, size, IPC_CREAT|IPC_EXCL|perm)) >= 0) 107 { 108 /* 109 * initialize all semaphores to 0 110 * this also sets the semaphore 0 ref count 111 */ 112 113 sem.sem_op = 1; 114 sem.sem_flg = 0; 115 for (sem.sem_num = 0; sem.sem_num < size; sem.sem_num++) 116 if (semop(id, &sem, 1) < 0) 117 { 118 (void)semctl(id, 0, IPC_RMID); 119 return 0; 120 } 121 break; 122 } 123 else if (errno == EINVAL && size > 3) 124 size /= 2; 125 else if (errno != EEXIST) 126 return 0; 127 else if ((id = semget(key, size, perm)) >= 0) 128 { 129 struct semid_ds ds; 130 Semun_t arg; 131 unsigned int k; 132 133 /* 134 * make sure all semaphores have been activated 135 */ 136 137 arg.ds = &ds; 138 for (k = 0; k < SPIN; ASOLOOP(k)) 139 { 140 if (semctl(id, size-1, IPC_STAT, arg) < 0) 141 return 0; 142 if (ds.sem_otime) 143 break; 144 } 145 if (k > SPIN) 146 return 0; 147 148 /* 149 * bump the ref count 150 */ 151 152 sem.sem_num = 0; 153 sem.sem_op = 1; 154 sem.sem_flg = 0; 155 if (semop(id, &sem, 1) < 0) 156 return 0; 157 break; 158 } 159 else if (errno == EINVAL && size > 3) 160 size /= 2; 161 else 162 return 0; 163 } 164 if (!(apl = newof(0, APL_t, 1, 0))) 165 return 0; 166 apl->id = id; 167 apl->size = size - 1; 168 return apl; 169} 170 171static ssize_t 172aso_lock_semaphore(void* data, ssize_t k, void volatile* p) 173{ 174 APL_t* apl = (APL_t*)data; 175 struct sembuf sem; 176 177 if (!apl) 178 return -1; 179 if (k > 0) 180 sem.sem_op = 1; 181 else 182 { 183 sem.sem_op = -1; 184 k = HASH(p, apl->size) + 1; 185 } 186 sem.sem_num = k; 187 sem.sem_flg = 0; 188 return semop(apl->id, &sem, 1) < 0 ? -1 : k; 189} 190 191Asometh_t _aso_meth_semaphore = { "semaphore", ASO_PROCESS|ASO_THREAD, aso_init_semaphore, aso_lock_semaphore }; 192 193#endif 194