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 28 NoN(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 38 typedef union Semun_u 39 { 40 int val; 41 struct semid_ds* ds; 42 unsigned short* array; 43 } Semun_t; 44 45 typedef struct APL_s 46 { 47 int id; 48 size_t size; 49 } APL_t; 50 51 static void* 52 aso_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 171 static ssize_t 172 aso_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 191 Asometh_t _aso_meth_semaphore = { "semaphore", ASO_PROCESS|ASO_THREAD, aso_init_semaphore, aso_lock_semaphore }; 192 193 #endif 194