1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #pragma weak sem_open = _sem_open 30 #pragma weak sem_close = _sem_close 31 #pragma weak sem_unlink = _sem_unlink 32 #pragma weak sem_init = _sem_init 33 #pragma weak sem_destroy = _sem_destroy 34 #pragma weak sem_wait = _sem_wait 35 #pragma weak sem_timedwait = _sem_timedwait 36 #pragma weak sem_reltimedwait_np = _sem_reltimedwait_np 37 #pragma weak sem_trywait = _sem_trywait 38 #pragma weak sem_post = _sem_post 39 #pragma weak sem_getvalue = _sem_getvalue 40 41 #include "synonyms.h" 42 #include "mtlib.h" 43 #include <sys/types.h> 44 #include <semaphore.h> 45 #include <synch.h> 46 #include <errno.h> 47 #include <stdarg.h> 48 #include <limits.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <sys/stat.h> 52 #include <sys/mman.h> 53 #include <unistd.h> 54 #include <thread.h> 55 #include "pos4obj.h" 56 57 typedef struct semaddr { 58 struct semaddr *sad_next; /* next in the link */ 59 char sad_name[PATH_MAX + 1]; /* name of sem object */ 60 sem_t *sad_addr; /* mmapped address of semaphore */ 61 ino64_t sad_inode; /* inode # of the mmapped file */ 62 } semaddr_t; 63 64 static long semvaluemax = 0; 65 static semaddr_t *semheadp = NULL; 66 static mutex_t semlock = DEFAULTMUTEX; 67 68 sem_t * 69 _sem_open(const char *path, int oflag, /* mode_t mode, int value */ ...) 70 { 71 va_list ap; 72 mode_t crmode = 0; 73 sem_t *sem = NULL; 74 struct stat64 statbuf; 75 semaddr_t *next = NULL; 76 int fd = 0; 77 int error = 0; 78 int cr_flag = 0; 79 uint_t value = 0; 80 81 if (__pos4obj_check(path) == -1) 82 return (SEM_FAILED); 83 84 /* acquire semaphore lock to have atomic operation */ 85 if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0) 86 return (SEM_FAILED); 87 88 /* modify oflag to have RDWR and filter CREATE mode only */ 89 oflag = (oflag & (O_CREAT|O_EXCL)) | (O_RDWR); 90 if (oflag & O_CREAT) { 91 if (semvaluemax == 0 && 92 (semvaluemax = _sysconf(_SC_SEM_VALUE_MAX)) <= 0) 93 semvaluemax = -1; 94 va_start(ap, oflag); 95 crmode = va_arg(ap, mode_t); 96 value = va_arg(ap, uint_t); 97 va_end(ap); 98 /* check value < the max for a named semaphore */ 99 if (semvaluemax < 0 || 100 (ulong_t)value > (ulong_t)semvaluemax) { 101 errno = EINVAL; 102 goto out; 103 } 104 } 105 106 errno = 0; 107 108 if ((fd = __pos4obj_open(path, SEM_DATA_TYPE, 109 oflag, crmode, &cr_flag)) < 0) 110 goto out; 111 112 if (cr_flag) 113 cr_flag = DFILE_CREATE | DFILE_OPEN; 114 else 115 cr_flag = DFILE_OPEN; 116 117 /* find out inode # for the opened file */ 118 if (fstat64(fd, &statbuf) < 0) 119 goto out; 120 121 /* if created, acquire total_size in the file */ 122 if ((cr_flag & DFILE_CREATE) != 0) { 123 if (ftruncate64(fd, (off64_t)sizeof (sem_t)) < 0) 124 goto out; 125 } else { 126 /* 127 * if this semaphore has already been opened, inode 128 * will indicate then return the same semaphore address 129 */ 130 lmutex_lock(&semlock); 131 for (next = semheadp; next != NULL; next = next->sad_next) { 132 if (statbuf.st_ino == next->sad_inode && 133 strcmp(path, next->sad_name) == 0) { 134 (void) __close_nc(fd); 135 lmutex_unlock(&semlock); 136 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE); 137 return (next->sad_addr); 138 } 139 } 140 lmutex_unlock(&semlock); 141 } 142 143 144 /* new sem descriptor to be allocated and new address to be mapped */ 145 if ((next = malloc(sizeof (semaddr_t))) == NULL) { 146 errno = ENOMEM; 147 goto out; 148 } 149 cr_flag |= ALLOC_MEM; 150 151 /* LINTED */ 152 sem = (sem_t *)mmap64(NULL, sizeof (sem_t), PROT_READ|PROT_WRITE, 153 MAP_SHARED, fd, (off64_t)0); 154 (void) __close_nc(fd); 155 cr_flag &= ~DFILE_OPEN; 156 if (sem == MAP_FAILED) 157 goto out; 158 cr_flag |= DFILE_MMAP; 159 160 /* if created, initialize */ 161 if (cr_flag & DFILE_CREATE) { 162 error = sema_init((sema_t *)sem, value, USYNC_PROCESS, 0); 163 if (error) { 164 errno = error; 165 goto out; 166 } 167 } 168 169 if (__pos4obj_unlock(path, SEM_LOCK_TYPE) == 0) { 170 /* add to the list pointed by semheadp */ 171 lmutex_lock(&semlock); 172 next->sad_next = semheadp; 173 semheadp = next; 174 next->sad_addr = sem; 175 next->sad_inode = statbuf.st_ino; 176 (void) strcpy(next->sad_name, path); 177 lmutex_unlock(&semlock); 178 return (sem); 179 } 180 /* fall into the error case */ 181 out: 182 error = errno; 183 if ((cr_flag & DFILE_OPEN) != 0) 184 (void) __close_nc(fd); 185 if ((cr_flag & DFILE_CREATE) != 0) 186 (void) __pos4obj_unlink(path, SEM_DATA_TYPE); 187 if ((cr_flag & ALLOC_MEM) != 0) 188 free(next); 189 if ((cr_flag & DFILE_MMAP) != 0) 190 (void) munmap((caddr_t)sem, sizeof (sem_t)); 191 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE); 192 errno = error; 193 return (SEM_FAILED); 194 } 195 196 int 197 _sem_close(sem_t *sem) 198 { 199 semaddr_t **next; 200 semaddr_t *freeit; 201 202 lmutex_lock(&semlock); 203 for (next = &semheadp; (freeit = *next) != NULL; 204 next = &(freeit->sad_next)) { 205 if (freeit->sad_addr == sem) { 206 *next = freeit->sad_next; 207 lmutex_unlock(&semlock); 208 free(freeit); 209 return (munmap((caddr_t)sem, sizeof (sem_t))); 210 } 211 } 212 lmutex_unlock(&semlock); 213 errno = EINVAL; 214 return (-1); 215 } 216 217 int 218 _sem_unlink(const char *path) 219 { 220 int error; 221 int oerrno; 222 223 if (__pos4obj_check(path) < 0) 224 return (-1); 225 226 if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0) 227 return (-1); 228 229 error = __pos4obj_unlink(path, SEM_DATA_TYPE); 230 231 oerrno = errno; 232 233 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE); 234 235 errno = oerrno; 236 237 return (error); 238 } 239 240 /* 241 * SUSV3 requires ("shall fail") an EINVAL failure for operations 242 * on invalid semaphores, including uninitialized unnamed semaphores. 243 * The best we can do is check that the magic number is correct. 244 * This is not perfect, but it allows the test suite to pass. 245 * (Standards bodies are filled with fools and idiots.) 246 */ 247 static int 248 sem_invalid(sem_t *sem) 249 { 250 if (sem->sem_magic != SEMA_MAGIC) { 251 errno = EINVAL; 252 return (-1); 253 } 254 return (0); 255 } 256 257 int 258 _sem_init(sem_t *sem, int pshared, uint_t value) 259 { 260 int error; 261 262 if ((error = sema_init((sema_t *)sem, value, 263 pshared ? USYNC_PROCESS : USYNC_THREAD, NULL)) != 0) { 264 errno = error; 265 return (-1); 266 } 267 return (0); 268 } 269 270 int 271 _sem_destroy(sem_t *sem) 272 { 273 int error; 274 275 if (sem_invalid(sem)) 276 return (-1); 277 if ((error = sema_destroy((sema_t *)sem)) != 0) { 278 errno = error; 279 return (-1); 280 } 281 return (0); 282 } 283 284 int 285 _sem_post(sem_t *sem) 286 { 287 int error; 288 289 if (sem_invalid(sem)) 290 return (-1); 291 if ((error = sema_post((sema_t *)sem)) != 0) { 292 errno = error; 293 return (-1); 294 } 295 return (0); 296 } 297 298 int 299 _sem_wait(sem_t *sem) 300 { 301 int error; 302 303 if (sem_invalid(sem)) 304 return (-1); 305 if ((error = sema_wait((sema_t *)sem)) != 0) { 306 errno = error; 307 return (-1); 308 } 309 return (0); 310 } 311 312 int 313 _sem_timedwait(sem_t *sem, const timespec_t *abstime) 314 { 315 int error; 316 317 if (sem_invalid(sem)) 318 return (-1); 319 if ((error = sema_timedwait((sema_t *)sem, abstime)) != 0) { 320 if (error == ETIME) 321 error = ETIMEDOUT; 322 errno = error; 323 return (-1); 324 } 325 return (0); 326 } 327 328 int 329 _sem_reltimedwait_np(sem_t *sem, const timespec_t *reltime) 330 { 331 int error; 332 333 if (sem_invalid(sem)) 334 return (-1); 335 if ((error = sema_reltimedwait((sema_t *)sem, reltime)) != 0) { 336 if (error == ETIME) 337 error = ETIMEDOUT; 338 errno = error; 339 return (-1); 340 } 341 return (0); 342 } 343 344 int 345 _sem_trywait(sem_t *sem) 346 { 347 int error; 348 349 if (sem_invalid(sem)) 350 return (-1); 351 if ((error = sema_trywait((sema_t *)sem)) != 0) { 352 if (error == EBUSY) 353 error = EAGAIN; 354 errno = error; 355 return (-1); 356 } 357 return (0); 358 } 359 360 int 361 _sem_getvalue(sem_t *sem, int *sval) 362 { 363 if (sem_invalid(sem)) 364 return (-1); 365 *sval = (int)sem->sem_count; 366 return (0); 367 } 368