]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/posix_sem.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / bsd / kern / posix_sem.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1990, 1996-1998 Apple Computer, Inc.
24 * All Rights Reserved.
25 */
26 /*
27 * posix_shm.c : Support for POSIX semaphore APIs
28 *
29 * File: posix_sem.c
30 * Author: Ananthakrishna Ramesh
31 *
32 * HISTORY
33 * 2-Sep-1999 A.Ramesh
34 * Created for MacOSX
35 *
36 */
37
38 #include <sys/cdefs.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/file.h>
43 #include <sys/filedesc.h>
44 #include <sys/stat.h>
45 #include <sys/buf.h>
46 #include <sys/proc.h>
47 #include <sys/mount.h>
48 #include <sys/namei.h>
49 #include <sys/vnode.h>
50 #include <sys/ioctl.h>
51 #include <sys/tty.h>
52 #include <sys/malloc.h>
53 #include <sys/semaphore.h>
54
55 #include <bsm/audit_kernel.h>
56
57 #include <mach/mach_types.h>
58 #include <mach/vm_prot.h>
59 #include <mach/semaphore.h>
60 #include <mach/sync_policy.h>
61 #include <kern/task.h>
62 #include <kern/clock.h>
63 #include <mach/kern_return.h>
64
65 #define PSEMNAMLEN 31 /* maximum name segment length we bother with */
66
67 struct pseminfo {
68 unsigned int psem_flags;
69 unsigned int psem_usecount;
70 mode_t psem_mode;
71 uid_t psem_uid;
72 gid_t psem_gid;
73 char psem_name[PSEMNAMLEN + 1]; /* segment name */
74 void * psem_semobject;
75 struct proc * sem_proc;
76 };
77 #define PSEMINFO_NULL (struct pseminfo *)0
78
79 #define PSEM_NONE 1
80 #define PSEM_DEFINED 2
81 #define PSEM_ALLOCATED 4
82 #define PSEM_MAPPED 8
83 #define PSEM_INUSE 0x10
84 #define PSEM_REMOVED 0x20
85 #define PSEM_INCREATE 0x40
86 #define PSEM_INDELETE 0x80
87
88 struct psemcache {
89 LIST_ENTRY(psemcache) psem_hash; /* hash chain */
90 struct pseminfo *pseminfo; /* vnode the name refers to */
91 int psem_nlen; /* length of name */
92 char psem_name[PSEMNAMLEN + 1]; /* segment name */
93 };
94 #define PSEMCACHE_NULL (struct psemcache *)0
95
96 struct psemstats {
97 long goodhits; /* hits that we can really use */
98 long neghits; /* negative hits that we can use */
99 long badhits; /* hits we must drop */
100 long falsehits; /* hits with id mismatch */
101 long miss; /* misses */
102 long longnames; /* long names that ignore cache */
103 };
104
105 struct psemname {
106 char *psem_nameptr; /* pointer to looked up name */
107 long psem_namelen; /* length of looked up component */
108 u_long psem_hash; /* hash value of looked up name */
109 };
110
111 struct psemnode {
112 struct pseminfo *pinfo;
113 #if DIAGNOSTIC
114 unsigned int readcnt;
115 unsigned int writecnt;
116 #endif
117 };
118 #define PSEMNODE_NULL (struct psemnode *)0
119
120
121 #define PSEMHASH(pnp) \
122 (&psemhashtbl[(pnp)->psem_hash & psemhash])
123 LIST_HEAD(psemhashhead, psemcache) *psemhashtbl; /* Hash Table */
124 u_long psemhash; /* size of hash table - 1 */
125 long psemnument; /* number of cache entries allocated */
126 struct psemstats psemstats; /* cache effectiveness statistics */
127
128 static int psem_cache_search __P((struct pseminfo **,
129 struct psemname *, struct psemcache **));
130
131 static int psem_read __P((struct file *fp, struct uio *uio,
132 struct ucred *cred, int flags, struct proc *p));
133 static int psem_write __P((struct file *fp, struct uio *uio,
134 struct ucred *cred, int flags, struct proc *p));
135 static int psem_ioctl __P((struct file *fp, u_long com,
136 caddr_t data, struct proc *p));
137 static int psem_select __P((struct file *fp, int which, void *wql,
138 struct proc *p));
139 static int psem_closefile __P((struct file *fp, struct proc *p));
140
141 static int psem_kqfilter __P((struct file *fp, struct knote *kn, struct proc *p));
142
143 struct fileops psemops =
144 { psem_read, psem_write, psem_ioctl, psem_select, psem_closefile, psem_kqfilter };
145
146 /*
147 * Lookup an entry in the cache
148 *
149 *
150 * status of -1 is returned if matches
151 * If the lookup determines that the name does not exist
152 * (negative cacheing), a status of ENOENT is returned. If the lookup
153 * fails, a status of zero is returned.
154 */
155
156 static int
157 psem_cache_search(psemp, pnp, pcache)
158 struct pseminfo **psemp;
159 struct psemname *pnp;
160 struct psemcache **pcache;
161 {
162 register struct psemcache *pcp, *nnp;
163 register struct psemhashhead *pcpp;
164
165 if (pnp->psem_namelen > PSEMNAMLEN) {
166 psemstats.longnames++;
167 return (0);
168 }
169
170 pcpp = PSEMHASH(pnp);
171 for (pcp = pcpp->lh_first; pcp != 0; pcp = nnp) {
172 nnp = pcp->psem_hash.le_next;
173 if (pcp->psem_nlen == pnp->psem_namelen &&
174 !bcmp(pcp->psem_name, pnp->psem_nameptr, (u_int)pcp-> psem_nlen))
175 break;
176 }
177
178 if (pcp == 0) {
179 psemstats.miss++;
180 return (0);
181 }
182
183 /* We found a "positive" match, return the vnode */
184 if (pcp->pseminfo) {
185 psemstats.goodhits++;
186 /* TOUCH(ncp); */
187 *psemp = pcp->pseminfo;
188 *pcache = pcp;
189 return (-1);
190 }
191
192 /*
193 * We found a "negative" match, ENOENT notifies client of this match.
194 * The nc_vpid field records whether this is a whiteout.
195 */
196 psemstats.neghits++;
197 return (ENOENT);
198 }
199
200 /*
201 * Add an entry to the cache.
202 */
203 static int
204 psem_cache_add(psemp, pnp)
205 struct pseminfo *psemp;
206 struct psemname *pnp;
207 {
208 register struct psemcache *pcp;
209 register struct psemhashhead *pcpp;
210 struct pseminfo *dpinfo;
211 struct psemcache *dpcp;
212
213 #if DIAGNOSTIC
214 if (pnp->psem_namelen > NCHNAMLEN)
215 panic("cache_enter: name too long");
216 #endif
217
218 /*
219 * We allocate a new entry if we are less than the maximum
220 * allowed and the one at the front of the LRU list is in use.
221 * Otherwise we use the one at the front of the LRU list.
222 */
223 pcp = (struct psemcache *)_MALLOC(sizeof(struct psemcache), M_SHM, M_WAITOK);
224 /* if the entry has already been added by some one else return */
225 if (psem_cache_search(&dpinfo, pnp, &dpcp) == -1) {
226 _FREE(pcp, M_SHM);
227 return(EEXIST);
228 }
229 psemnument++;
230
231 bzero(pcp, sizeof(struct psemcache));
232 /*
233 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
234 * For negative entries, we have to record whether it is a whiteout.
235 * the whiteout flag is stored in the nc_vpid field which is
236 * otherwise unused.
237 */
238 pcp->pseminfo = psemp;
239 pcp->psem_nlen = pnp->psem_namelen;
240 bcopy(pnp->psem_nameptr, pcp->psem_name, (unsigned)pcp->psem_nlen);
241 pcpp = PSEMHASH(pnp);
242 #if DIAGNOSTIC
243 {
244 register struct psemcache *p;
245
246 for (p = pcpp->lh_first; p != 0; p = p->psem_hash.le_next)
247 if (p == pcp)
248 panic("psem:cache_enter duplicate");
249 }
250 #endif
251 LIST_INSERT_HEAD(pcpp, pcp, psem_hash);
252 return(0);
253 }
254
255 /*
256 * Name cache initialization, from vfs_init() when we are booting
257 */
258 void
259 psem_cache_init()
260 {
261 psemhashtbl = hashinit(desiredvnodes, M_SHM, &psemhash);
262 }
263
264 static void
265 psem_cache_delete(pcp)
266 struct psemcache *pcp;
267 {
268 #if DIAGNOSTIC
269 if (pcp->psem_hash.le_prev == 0)
270 panic("psem namecache purge le_prev");
271 if (pcp->psem_hash.le_next == pcp)
272 panic("namecache purge le_next");
273 #endif /* DIAGNOSTIC */
274 LIST_REMOVE(pcp, psem_hash);
275 pcp->psem_hash.le_prev = 0;
276 psemnument--;
277 }
278
279 /*
280 * Invalidate a all entries to particular vnode.
281 *
282 * We actually just increment the v_id, that will do it. The entries will
283 * be purged by lookup as they get found. If the v_id wraps around, we
284 * need to ditch the entire cache, to avoid confusion. No valid vnode will
285 * ever have (v_id == 0).
286 */
287 void
288 psem_cache_purge(void)
289 {
290 struct psemcache *pcp;
291 struct psemhashhead *pcpp;
292
293 for (pcpp = &psemhashtbl[psemhash]; pcpp >= psemhashtbl; pcpp--) {
294 while (pcp = pcpp->lh_first)
295 psem_cache_delete(pcp);
296 }
297 }
298
299 struct sem_open_args {
300 const char *name;
301 int oflag;
302 int mode;
303 int value;
304 };
305
306 int
307 sem_open(p, uap, retval)
308 struct proc *p;
309 register struct sem_open_args *uap;
310 register_t *retval;
311 {
312 register struct filedesc *fdp = p->p_fd;
313 register struct file *fp;
314 register struct vnode *vp;
315 int i;
316 struct file *nfp;
317 int type, indx, error;
318 struct psemname nd;
319 struct pseminfo *pinfo;
320 extern struct fileops psemops;
321 char * pnbuf;
322 char * nameptr;
323 char * cp;
324 size_t pathlen, plen;
325 int fmode ;
326 int cmode = uap->mode;
327 int value = uap->value;
328 int incache = 0;
329 struct psemnode * pnode = PSEMNODE_NULL;
330 struct psemcache * pcache = PSEMCACHE_NULL;
331 kern_return_t kret = KERN_SUCCESS;
332 int pinfo_alloc = 0;
333
334 AUDIT_ARG(fflags, uap->oflag);
335 AUDIT_ARG(mode, uap->mode);
336 AUDIT_ARG(value, uap->value);
337 pinfo = PSEMINFO_NULL;
338
339 MALLOC_ZONE(pnbuf, caddr_t,
340 MAXPATHLEN, M_NAMEI, M_WAITOK);
341 pathlen = MAXPATHLEN;
342 error = copyinstr((void *)uap->name, pnbuf,
343 MAXPATHLEN, &pathlen);
344 if (error) {
345 goto bad;
346 }
347 AUDIT_ARG(text, pnbuf);
348 if (pathlen > PSEMNAMLEN) {
349 error = ENAMETOOLONG;
350 goto bad;
351 }
352
353 #ifdef PSXSEM_NAME_RESTRICT
354 nameptr = pnbuf;
355 if (*nameptr == '/') {
356 while (*(nameptr++) == '/') {
357 plen--;
358 error = EINVAL;
359 goto bad;
360 }
361 } else {
362 error = EINVAL;
363 goto bad;
364 }
365 #endif /* PSXSEM_NAME_RESTRICT */
366
367 plen = pathlen;
368 nameptr = pnbuf;
369 nd.psem_nameptr = nameptr;
370 nd.psem_namelen = plen;
371 nd. psem_hash =0;
372
373 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
374 nd.psem_hash += (unsigned char)*cp * i;
375 }
376
377 error = psem_cache_search(&pinfo, &nd, &pcache);
378
379 if (error == ENOENT) {
380 error = EINVAL;
381 goto bad;
382
383 }
384 if (!error) {
385 incache = 0;
386 } else
387 incache = 1;
388 fmode = FFLAGS(uap->oflag);
389
390 if (error = falloc(p, &nfp, &indx)) {
391 goto bad;
392 }
393
394 fp = nfp;
395 cmode &= ALLPERMS;
396
397 if (((fmode & (O_CREAT | O_EXCL))==(O_CREAT | O_EXCL)) && incache) {
398 /* sem exists and opened O_EXCL */
399 #if notyet
400 if (pinfo->psem_flags & PSEM_INDELETE) {
401 }
402 #endif
403 AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid,
404 pinfo->psem_gid, pinfo->psem_mode);
405 error = EEXIST;
406 goto bad1;
407 }
408 if (((fmode & (O_CREAT | O_EXCL))== O_CREAT) && incache) {
409 /* As per POSIX, O_CREAT has no effect */
410 fmode &= ~O_CREAT;
411 }
412
413 if (fmode & O_CREAT) {
414 if((value < 0) && (value > SEM_VALUE_MAX)) {
415 error = EINVAL;
416 goto bad1;
417 }
418 pinfo = (struct pseminfo *)_MALLOC(sizeof(struct pseminfo), M_SHM, M_WAITOK);
419 bzero(pinfo, sizeof(struct pseminfo));
420 pinfo_alloc = 1;
421 pinfo->psem_flags = PSEM_DEFINED | PSEM_INCREATE;
422 pinfo->psem_usecount = 1;
423 pinfo->psem_mode = cmode;
424 pinfo->psem_uid = p->p_ucred->cr_uid;
425 pinfo->psem_gid = p->p_ucred->cr_gid;
426 kret = semaphore_create(kernel_task, &pinfo->psem_semobject,
427 SYNC_POLICY_FIFO, value);
428 if(kret != KERN_SUCCESS)
429 goto bad3;
430 pinfo->psem_flags &= ~PSEM_DEFINED;
431 pinfo->psem_flags |= PSEM_ALLOCATED;
432 pinfo->sem_proc = p;
433 } else {
434 /* semaphore should exist as it is without O_CREAT */
435 if (!incache) {
436 error = ENOENT;
437 goto bad1;
438 }
439 if( pinfo->psem_flags & PSEM_INDELETE) {
440 error = ENOENT;
441 goto bad1;
442 }
443 AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid,
444 pinfo->psem_gid, pinfo->psem_mode);
445 if (error = psem_access(pinfo, fmode, p->p_ucred, p))
446 goto bad1;
447 }
448 pnode = (struct psemnode *)_MALLOC(sizeof(struct psemnode), M_SHM, M_WAITOK);
449 bzero(pnode, sizeof(struct psemnode));
450
451 if (!incache) {
452 if (error = psem_cache_add(pinfo, &nd)) {
453 goto bad2;
454 }
455 }
456 pinfo->psem_flags &= ~PSEM_INCREATE;
457 pinfo->psem_usecount++;
458 pnode->pinfo = pinfo;
459 fp->f_flag = fmode & FMASK;
460 fp->f_type = DTYPE_PSXSEM;
461 fp->f_ops = &psemops;
462 fp->f_data = (caddr_t)pnode;
463 *fdflags(p, indx) &= ~UF_RESERVED;
464 *retval = indx;
465 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
466 return (0);
467
468 bad3:
469 switch (kret) {
470 case KERN_RESOURCE_SHORTAGE:
471 error = ENOMEM;
472 case KERN_PROTECTION_FAILURE:
473 error = EACCES;
474 default:
475 error = EINVAL;
476 }
477 goto bad1;
478 bad2:
479 _FREE(pnode, M_SHM);
480 if (pinfo_alloc)
481 _FREE(pinfo, M_SHM);
482 bad1:
483 fdrelse(p, indx);
484 ffree(nfp);
485 bad:
486 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
487 return (error);
488 }
489
490 int
491 psem_access(pinfo, mode, cred, p)
492 struct pseminfo *pinfo;
493 int mode;
494 struct ucred *cred;
495 struct proc *p;
496 {
497 mode_t mask;
498 register gid_t *gp;
499 int i, error;
500
501 /* Otherwise, user id 0 always gets access. */
502 if (cred->cr_uid == 0)
503 return (0);
504
505 mask = 0;
506
507 /* Otherwise, check the owner. */
508 if (cred->cr_uid == pinfo->psem_uid) {
509 if (mode & FREAD)
510 mask |= S_IRUSR;
511 if (mode & FWRITE)
512 mask |= S_IWUSR;
513 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
514 }
515
516 /* Otherwise, check the groups. */
517 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
518 if (pinfo->psem_gid == *gp) {
519 if (mode & FREAD)
520 mask |= S_IRGRP;
521 if (mode & FWRITE)
522 mask |= S_IWGRP;
523 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
524 }
525
526 /* Otherwise, check everyone else. */
527 if (mode & FREAD)
528 mask |= S_IROTH;
529 if (mode & FWRITE)
530 mask |= S_IWOTH;
531 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
532 }
533
534 struct sem_unlink_args {
535 const char *name;
536 };
537
538 int
539 sem_unlink(p, uap, retval)
540 struct proc *p;
541 register struct sem_unlink_args *uap;
542 register_t *retval;
543 {
544 register struct filedesc *fdp = p->p_fd;
545 register struct file *fp;
546 int flags, i;
547 int error=0;
548 struct psemname nd;
549 struct pseminfo *pinfo;
550 extern struct fileops psemops;
551 char * pnbuf;
552 char * nameptr;
553 char * cp;
554 size_t pathlen, plen;
555 int fmode, cmode ;
556 int incache = 0;
557 struct psemnode * pnode = PSEMNODE_NULL;
558 struct psemcache *pcache = PSEMCACHE_NULL;
559 kern_return_t kret;
560
561 pinfo = PSEMINFO_NULL;
562
563 MALLOC_ZONE(pnbuf, caddr_t,
564 MAXPATHLEN, M_NAMEI, M_WAITOK);
565 pathlen = MAXPATHLEN;
566 error = copyinstr((void *)uap->name, pnbuf,
567 MAXPATHLEN, &pathlen);
568 if (error) {
569 goto bad;
570 }
571 AUDIT_ARG(text, pnbuf);
572 if (pathlen > PSEMNAMLEN) {
573 error = ENAMETOOLONG;
574 goto bad;
575 }
576
577
578 #ifdef PSXSEM_NAME_RESTRICT
579 nameptr = pnbuf;
580 if (*nameptr == '/') {
581 while (*(nameptr++) == '/') {
582 plen--;
583 error = EINVAL;
584 goto bad;
585 }
586 } else {
587 error = EINVAL;
588 goto bad;
589 }
590 #endif /* PSXSEM_NAME_RESTRICT */
591
592 plen = pathlen;
593 nameptr = pnbuf;
594 nd.psem_nameptr = nameptr;
595 nd.psem_namelen = plen;
596 nd. psem_hash =0;
597
598 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
599 nd.psem_hash += (unsigned char)*cp * i;
600 }
601
602 error = psem_cache_search(&pinfo, &nd, &pcache);
603
604 if (error == ENOENT) {
605 error = EINVAL;
606 goto bad;
607
608 }
609 if (!error) {
610 error = EINVAL;
611 goto bad;
612 } else
613 incache = 1;
614 if (error = psem_access(pinfo, pinfo->psem_mode, p->p_ucred, p))
615 goto bad;
616
617 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))==0) {
618 return (EINVAL);
619 }
620
621 if (pinfo->psem_flags & PSEM_INDELETE) {
622 error = 0;
623 goto bad;
624 }
625 AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid, pinfo->psem_gid,
626 pinfo->psem_mode);
627
628 pinfo->psem_flags |= PSEM_INDELETE;
629 pinfo->psem_usecount--;
630
631 if (!pinfo->psem_usecount) {
632 psem_delete(pinfo);
633 _FREE(pinfo,M_SHM);
634 } else
635 pinfo->psem_flags |= PSEM_REMOVED;
636
637 psem_cache_delete(pcache);
638 _FREE(pcache, M_SHM);
639 error = 0;
640 bad:
641 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
642 return (error);
643 }
644
645 struct sem_close_args {
646 sem_t *sem;
647 };
648
649 int
650 sem_close(p, uap, retval)
651 struct proc *p;
652 struct sem_close_args *uap;
653 register_t *retval;
654 {
655 int fd = (int)uap->sem;
656 register struct filedesc *fdp = p->p_fd;
657 register struct file *fp;
658 int error = 0;
659
660 AUDIT_ARG(fd, fd); /* XXX This seems wrong; uap->sem is a pointer */
661 if ((u_int)fd >= fdp->fd_nfiles ||
662 (fp = fdp->fd_ofiles[fd]) == NULL ||
663 (fdp->fd_ofileflags[fd] & UF_RESERVED))
664 return (EBADF);
665 fdrelse(p, fd);
666 if( error = closef(fp, p))
667 return(error);
668 return(0);
669 }
670
671 struct sem_wait_args {
672 sem_t *sem;
673 };
674
675 int
676 sem_wait(p, uap, retval)
677 struct proc *p;
678 struct sem_wait_args *uap;
679 register_t *retval;
680 {
681 int fd = (int)uap->sem;
682 register struct filedesc *fdp = p->p_fd;
683 struct file *fp;
684 struct pseminfo * pinfo;
685 struct psemnode * pnode ;
686 kern_return_t kret;
687 int error;
688
689 if (error = fdgetf(p, (int)uap->sem, &fp))
690 return (error);
691 if (fp->f_type != DTYPE_PSXSEM)
692 return(EBADF);
693 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
694 return(EINVAL);
695 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
696 return(EINVAL);
697 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
698 != PSEM_ALLOCATED) {
699 return(EINVAL);
700 }
701
702 kret = semaphore_wait(pinfo->psem_semobject);
703 switch (kret) {
704 case KERN_INVALID_ADDRESS:
705 case KERN_PROTECTION_FAILURE:
706 return (EACCES);
707 case KERN_ABORTED:
708 case KERN_OPERATION_TIMED_OUT:
709 return (EINTR);
710 case KERN_SUCCESS:
711 return(0);
712 default:
713 return (EINVAL);
714 }
715 }
716
717 struct sem_trywait_args {
718 sem_t *sem;
719 };
720
721 int
722 sem_trywait(p, uap, retval)
723 struct proc *p;
724 struct sem_trywait_args *uap;
725 register_t *retval;
726 {
727 int fd = (int)uap->sem;
728 register struct filedesc *fdp = p->p_fd;
729 struct file *fp;
730 struct pseminfo * pinfo;
731 struct psemnode * pnode ;
732 kern_return_t kret;
733 mach_timespec_t wait_time;
734 int error;
735
736 if (error = fdgetf(p, (int)uap->sem, &fp))
737 return (error);
738 if (fp->f_type != DTYPE_PSXSEM)
739 return(EBADF);
740 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
741 return(EINVAL);
742 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
743 return(EINVAL);
744 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
745 != PSEM_ALLOCATED) {
746 return(EINVAL);
747 }
748
749 wait_time.tv_sec = 0;
750 wait_time.tv_nsec = 0;
751
752 kret = semaphore_timedwait(pinfo->psem_semobject, MACH_TIMESPEC_ZERO);
753 switch (kret) {
754 case KERN_INVALID_ADDRESS:
755 case KERN_PROTECTION_FAILURE:
756 return (EINVAL);
757 case KERN_ABORTED:
758 return (EINTR);
759 case KERN_OPERATION_TIMED_OUT:
760 return (EAGAIN);
761 case KERN_SUCCESS:
762 return(0);
763 default:
764 return (EINVAL);
765 }
766 }
767
768 struct sem_post_args {
769 sem_t *sem;
770 };
771
772 int
773 sem_post(p, uap, retval)
774 struct proc *p;
775 struct sem_post_args *uap;
776 register_t *retval;
777 {
778 int fd = (int)uap->sem;
779 register struct filedesc *fdp = p->p_fd;
780 struct file *fp;
781 struct pseminfo * pinfo;
782 struct psemnode * pnode ;
783 kern_return_t kret;
784 int error;
785
786 if (error = fdgetf(p, (int)uap->sem, &fp))
787 return (error);
788 if (fp->f_type != DTYPE_PSXSEM)
789 return(EBADF);
790 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
791 return(EINVAL);
792 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
793 return(EINVAL);
794 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
795 != PSEM_ALLOCATED) {
796 return(EINVAL);
797 }
798
799 kret = semaphore_signal(pinfo->psem_semobject);
800 switch (kret) {
801 case KERN_INVALID_ADDRESS:
802 case KERN_PROTECTION_FAILURE:
803 return (EINVAL);
804 case KERN_ABORTED:
805 case KERN_OPERATION_TIMED_OUT:
806 return (EINTR);
807 case KERN_SUCCESS:
808 return(0);
809 default:
810 return (EINVAL);
811 }
812 }
813
814 struct sem_init_args {
815 sem_t *sem;
816 int phsared;
817 unsigned int value;
818 };
819
820 int
821 sem_init(p, uap, retval)
822 struct proc *p;
823 struct sem_init_args *uap;
824 register_t *retval;
825 {
826 return(ENOSYS);
827 }
828
829 struct sem_destroy_args {
830 sem_t *sem;
831 };
832
833 int
834 sem_destroy(p, uap, retval)
835 struct proc *p;
836 struct sem_destroy_args *uap;
837 register_t *retval;
838 {
839 return(ENOSYS);
840 }
841
842 struct sem_getvalue_args {
843 sem_t *sem;
844 int * sval;
845 };
846
847 int
848 sem_getvalue(p, uap, retval)
849 struct proc *p;
850 struct sem_getvalue_args *uap;
851 register_t *retval;
852 {
853 return(ENOSYS);
854 }
855
856 static int
857 psem_close(pnode, flags, cred, p)
858 register struct psemnode *pnode;
859 int flags;
860 struct ucred *cred;
861 struct proc *p;
862 {
863 int error=0;
864 kern_return_t kret;
865 register struct pseminfo *pinfo;
866
867 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
868 return(EINVAL);
869
870 if ((pinfo->psem_flags & PSEM_ALLOCATED) != PSEM_ALLOCATED) {
871 return(EINVAL);
872 }
873 #if DIAGNOSTIC
874 if(!pinfo->psem_usecount) {
875 kprintf("negative usecount in psem_close\n");
876 }
877 #endif /* DIAGNOSTIC */
878 pinfo->psem_usecount--;
879
880 if ((pinfo->psem_flags & PSEM_REMOVED) && !pinfo->psem_usecount) {
881 error = psem_delete(pinfo);
882 _FREE(pinfo,M_SHM);
883 }
884 _FREE(pnode, M_SHM);
885 return (error);
886 }
887
888 static int
889 psem_closefile(fp, p)
890 struct file *fp;
891 struct proc *p;
892 {
893
894 return (psem_close(((struct psemnode *)fp->f_data), fp->f_flag,
895 fp->f_cred, p));
896 }
897
898 int
899 psem_delete(struct pseminfo * pinfo)
900 {
901 kern_return_t kret;
902
903 kret = semaphore_destroy(kernel_task, pinfo->psem_semobject);
904
905 switch (kret) {
906 case KERN_INVALID_ADDRESS:
907 case KERN_PROTECTION_FAILURE:
908 return (EINVAL);
909 case KERN_ABORTED:
910 case KERN_OPERATION_TIMED_OUT:
911 return (EINTR);
912 case KERN_SUCCESS:
913 return(0);
914 default:
915 return (EINVAL);
916 }
917 }
918
919 static int
920 psem_read(fp, uio, cred, flags, p)
921 struct file *fp;
922 struct uio *uio;
923 struct ucred *cred;
924 int flags;
925 struct proc *p;
926 {
927 return(EOPNOTSUPP);
928 }
929
930 static int
931 psem_write(fp, uio, cred, flags, p)
932 struct file *fp;
933 struct uio *uio;
934 struct ucred *cred;
935 int flags;
936 struct proc *p;
937 {
938 return(EOPNOTSUPP);
939 }
940
941 static int
942 psem_ioctl(fp, com, data, p)
943 struct file *fp;
944 u_long com;
945 caddr_t data;
946 struct proc *p;
947 {
948 return(EOPNOTSUPP);
949 }
950
951 static int
952 psem_select(fp, which, wql, p)
953 struct file *fp;
954 int which;
955 void *wql;
956 struct proc *p;
957 {
958 return(EOPNOTSUPP);
959 }
960
961 static int
962 psem_kqfilter(fp, kn, p)
963 struct file *fp;
964 struct knote *kn;
965 struct proc *p;
966 {
967 return (EOPNOTSUPP);
968 }
969