]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/posix_sem.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / kern / posix_sem.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1990, 1996-1998 Apple Computer, Inc.
27 * All Rights Reserved.
28 */
29 /*
30 * posix_shm.c : Support for POSIX semaphore APIs
31 *
32 * File: posix_sem.c
33 * Author: Ananthakrishna Ramesh
34 *
35 * HISTORY
36 * 2-Sep-1999 A.Ramesh
37 * Created for MacOSX
38 *
39 */
40
41 #include <sys/cdefs.h>
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/file.h>
46 #include <sys/filedesc.h>
47 #include <sys/stat.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/mount.h>
51 #include <sys/namei.h>
52 #include <sys/vnode.h>
53 #include <sys/ioctl.h>
54 #include <sys/tty.h>
55 #include <sys/malloc.h>
56 #include <sys/semaphore.h>
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 pinfo = PSEMINFO_NULL;
335
336 MALLOC_ZONE(pnbuf, caddr_t,
337 MAXPATHLEN, M_NAMEI, M_WAITOK);
338 pathlen = MAXPATHLEN;
339 error = copyinstr((void *)uap->name, pnbuf,
340 MAXPATHLEN, &pathlen);
341 if (error) {
342 goto bad;
343 }
344 if (pathlen > PSEMNAMLEN) {
345 error = ENAMETOOLONG;
346 goto bad;
347 }
348
349 #ifdef PSXSEM_NAME_RESTRICT
350 nameptr = pnbuf;
351 if (*nameptr == '/') {
352 while (*(nameptr++) == '/') {
353 plen--;
354 error = EINVAL;
355 goto bad;
356 }
357 } else {
358 error = EINVAL;
359 goto bad;
360 }
361 #endif /* PSXSEM_NAME_RESTRICT */
362
363 plen = pathlen;
364 nameptr = pnbuf;
365 nd.psem_nameptr = nameptr;
366 nd.psem_namelen = plen;
367 nd. psem_hash =0;
368
369 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
370 nd.psem_hash += (unsigned char)*cp * i;
371 }
372
373 error = psem_cache_search(&pinfo, &nd, &pcache);
374
375 if (error == ENOENT) {
376 error = EINVAL;
377 goto bad;
378
379 }
380 if (!error) {
381 incache = 0;
382 } else
383 incache = 1;
384 fmode = FFLAGS(uap->oflag);
385
386 if (error = falloc(p, &nfp, &indx)) {
387 goto bad;
388 }
389
390 fp = nfp;
391 cmode &= ALLPERMS;
392
393 if (((fmode & (O_CREAT | O_EXCL))==(O_CREAT | O_EXCL)) && incache) {
394 /* sem exists and opened O_EXCL */
395 #if notyet
396 if (pinfo->psem_flags & PSEM_INDELETE) {
397 }
398 #endif
399 error = EEXIST;
400 goto bad1;
401 }
402 if (((fmode & (O_CREAT | O_EXCL))== O_CREAT) && incache) {
403 /* As per POSIX, O_CREAT has no effect */
404 fmode &= ~O_CREAT;
405 }
406
407 if (fmode & O_CREAT) {
408 if((value < 0) && (value > SEM_VALUE_MAX)) {
409 error = EINVAL;
410 goto bad1;
411 }
412 pinfo = (struct pseminfo *)_MALLOC(sizeof(struct pseminfo), M_SHM, M_WAITOK);
413 bzero(pinfo, sizeof(struct pseminfo));
414 pinfo_alloc = 1;
415 pinfo->psem_flags = PSEM_DEFINED | PSEM_INCREATE;
416 pinfo->psem_usecount = 1;
417 pinfo->psem_mode = cmode;
418 pinfo->psem_uid = p->p_ucred->cr_uid;
419 pinfo->psem_gid = p->p_ucred->cr_gid;
420 kret = semaphore_create(kernel_task, &pinfo->psem_semobject,
421 SYNC_POLICY_FIFO, value);
422 if(kret != KERN_SUCCESS)
423 goto bad3;
424 pinfo->psem_flags &= ~PSEM_DEFINED;
425 pinfo->psem_flags |= PSEM_ALLOCATED;
426 pinfo->sem_proc = p;
427 } else {
428 /* semaphore should exist as it is without O_CREAT */
429 if (!incache) {
430 error = ENOENT;
431 goto bad1;
432 }
433 if( pinfo->psem_flags & PSEM_INDELETE) {
434 error = ENOENT;
435 goto bad1;
436 }
437 if (error = psem_access(pinfo, fmode, p->p_ucred, p))
438 goto bad1;
439 }
440 pnode = (struct psemnode *)_MALLOC(sizeof(struct psemnode), M_SHM, M_WAITOK);
441 bzero(pnode, sizeof(struct psemnode));
442
443 if (!incache) {
444 if (error = psem_cache_add(pinfo, &nd)) {
445 goto bad2;
446 }
447 }
448 pinfo->psem_flags &= ~PSEM_INCREATE;
449 pinfo->psem_usecount++;
450 pnode->pinfo = pinfo;
451 fp->f_flag = fmode & FMASK;
452 fp->f_type = DTYPE_PSXSEM;
453 fp->f_ops = &psemops;
454 fp->f_data = (caddr_t)pnode;
455 *fdflags(p, indx) &= ~UF_RESERVED;
456 *retval = indx;
457 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
458 return (0);
459
460 bad3:
461 switch (kret) {
462 case KERN_RESOURCE_SHORTAGE:
463 error = ENOMEM;
464 case KERN_PROTECTION_FAILURE:
465 error = EACCES;
466 default:
467 error = EINVAL;
468 }
469 goto bad1;
470 bad2:
471 _FREE(pnode, M_SHM);
472 if (pinfo_alloc)
473 _FREE(pinfo, M_SHM);
474 bad1:
475 fdrelse(p, indx);
476 ffree(nfp);
477 bad:
478 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
479 return (error);
480 }
481
482 int
483 psem_access(pinfo, mode, cred, p)
484 struct pseminfo *pinfo;
485 int mode;
486 struct ucred *cred;
487 struct proc *p;
488 {
489 mode_t mask;
490 register gid_t *gp;
491 int i, error;
492
493 /* Otherwise, user id 0 always gets access. */
494 if (cred->cr_uid == 0)
495 return (0);
496
497 mask = 0;
498
499 /* Otherwise, check the owner. */
500 if (cred->cr_uid == pinfo->psem_uid) {
501 if (mode & FREAD)
502 mask |= S_IRUSR;
503 if (mode & FWRITE)
504 mask |= S_IWUSR;
505 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
506 }
507
508 /* Otherwise, check the groups. */
509 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
510 if (pinfo->psem_gid == *gp) {
511 if (mode & FREAD)
512 mask |= S_IRGRP;
513 if (mode & FWRITE)
514 mask |= S_IWGRP;
515 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
516 }
517
518 /* Otherwise, check everyone else. */
519 if (mode & FREAD)
520 mask |= S_IROTH;
521 if (mode & FWRITE)
522 mask |= S_IWOTH;
523 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
524 }
525
526 struct sem_unlink_args {
527 const char *name;
528 };
529
530 int
531 sem_unlink(p, uap, retval)
532 struct proc *p;
533 register struct sem_unlink_args *uap;
534 register_t *retval;
535 {
536 register struct filedesc *fdp = p->p_fd;
537 register struct file *fp;
538 int flags, i;
539 int error=0;
540 struct psemname nd;
541 struct pseminfo *pinfo;
542 extern struct fileops psemops;
543 char * pnbuf;
544 char * nameptr;
545 char * cp;
546 size_t pathlen, plen;
547 int fmode, cmode ;
548 int incache = 0;
549 struct psemnode * pnode = PSEMNODE_NULL;
550 struct psemcache *pcache = PSEMCACHE_NULL;
551 kern_return_t kret;
552
553 pinfo = PSEMINFO_NULL;
554
555 MALLOC_ZONE(pnbuf, caddr_t,
556 MAXPATHLEN, M_NAMEI, M_WAITOK);
557 pathlen = MAXPATHLEN;
558 error = copyinstr((void *)uap->name, pnbuf,
559 MAXPATHLEN, &pathlen);
560 if (error) {
561 goto bad;
562 }
563 if (pathlen > PSEMNAMLEN) {
564 error = ENAMETOOLONG;
565 goto bad;
566 }
567
568
569 #ifdef PSXSEM_NAME_RESTRICT
570 nameptr = pnbuf;
571 if (*nameptr == '/') {
572 while (*(nameptr++) == '/') {
573 plen--;
574 error = EINVAL;
575 goto bad;
576 }
577 } else {
578 error = EINVAL;
579 goto bad;
580 }
581 #endif /* PSXSEM_NAME_RESTRICT */
582
583 plen = pathlen;
584 nameptr = pnbuf;
585 nd.psem_nameptr = nameptr;
586 nd.psem_namelen = plen;
587 nd. psem_hash =0;
588
589 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
590 nd.psem_hash += (unsigned char)*cp * i;
591 }
592
593 error = psem_cache_search(&pinfo, &nd, &pcache);
594
595 if (error == ENOENT) {
596 error = EINVAL;
597 goto bad;
598
599 }
600 if (!error) {
601 error = EINVAL;
602 goto bad;
603 } else
604 incache = 1;
605 if (error = psem_access(pinfo, pinfo->psem_mode, p->p_ucred, p))
606 goto bad;
607
608 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))==0) {
609 return (EINVAL);
610 }
611
612 if (pinfo->psem_flags & PSEM_INDELETE) {
613 error = 0;
614 goto bad;
615 }
616 pinfo->psem_flags |= PSEM_INDELETE;
617 pinfo->psem_usecount--;
618
619 if (!pinfo->psem_usecount) {
620 psem_delete(pinfo);
621 _FREE(pinfo,M_SHM);
622 } else
623 pinfo->psem_flags |= PSEM_REMOVED;
624
625 psem_cache_delete(pcache);
626 _FREE(pcache, M_SHM);
627 error = 0;
628 bad:
629 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
630 return (error);
631 }
632
633 struct sem_close_args {
634 sem_t *sem;
635 };
636
637 int
638 sem_close(p, uap, retval)
639 struct proc *p;
640 struct sem_close_args *uap;
641 register_t *retval;
642 {
643 int fd = (int)uap->sem;
644 register struct filedesc *fdp = p->p_fd;
645 register struct file *fp;
646 int error = 0;
647
648
649 if ((u_int)fd >= fdp->fd_nfiles ||
650 (fp = fdp->fd_ofiles[fd]) == NULL ||
651 (fdp->fd_ofileflags[fd] & UF_RESERVED))
652 return (EBADF);
653 fdrelse(p, fd);
654 if( error = closef(fp, p))
655 return(error);
656 return(0);
657 }
658
659 struct sem_wait_args {
660 sem_t *sem;
661 };
662
663 int
664 sem_wait(p, uap, retval)
665 struct proc *p;
666 struct sem_wait_args *uap;
667 register_t *retval;
668 {
669 int fd = (int)uap->sem;
670 register struct filedesc *fdp = p->p_fd;
671 struct file *fp;
672 struct pseminfo * pinfo;
673 struct psemnode * pnode ;
674 kern_return_t kret;
675 int error;
676
677 if (error = fdgetf(p, (int)uap->sem, &fp))
678 return (error);
679 if (fp->f_type != DTYPE_PSXSEM)
680 return(EBADF);
681 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
682 return(EINVAL);
683 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
684 return(EINVAL);
685 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
686 != PSEM_ALLOCATED) {
687 return(EINVAL);
688 }
689
690 kret = semaphore_wait(pinfo->psem_semobject);
691 switch (kret) {
692 case KERN_INVALID_ADDRESS:
693 case KERN_PROTECTION_FAILURE:
694 return (EACCES);
695 case KERN_ABORTED:
696 case KERN_OPERATION_TIMED_OUT:
697 return (EINTR);
698 case KERN_SUCCESS:
699 return(0);
700 default:
701 return (EINVAL);
702 }
703 }
704
705 struct sem_trywait_args {
706 sem_t *sem;
707 };
708
709 int
710 sem_trywait(p, uap, retval)
711 struct proc *p;
712 struct sem_trywait_args *uap;
713 register_t *retval;
714 {
715 int fd = (int)uap->sem;
716 register struct filedesc *fdp = p->p_fd;
717 struct file *fp;
718 struct pseminfo * pinfo;
719 struct psemnode * pnode ;
720 kern_return_t kret;
721 mach_timespec_t wait_time;
722 int error;
723
724 if (error = fdgetf(p, (int)uap->sem, &fp))
725 return (error);
726 if (fp->f_type != DTYPE_PSXSEM)
727 return(EBADF);
728 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
729 return(EINVAL);
730 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
731 return(EINVAL);
732 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
733 != PSEM_ALLOCATED) {
734 return(EINVAL);
735 }
736
737 wait_time.tv_sec = 0;
738 wait_time.tv_nsec = 0;
739
740 kret = semaphore_timedwait(pinfo->psem_semobject, MACH_TIMESPEC_ZERO);
741 switch (kret) {
742 case KERN_INVALID_ADDRESS:
743 case KERN_PROTECTION_FAILURE:
744 return (EINVAL);
745 case KERN_ABORTED:
746 return (EINTR);
747 case KERN_OPERATION_TIMED_OUT:
748 return (EAGAIN);
749 case KERN_SUCCESS:
750 return(0);
751 default:
752 return (EINVAL);
753 }
754 }
755
756 struct sem_post_args {
757 sem_t *sem;
758 };
759
760 int
761 sem_post(p, uap, retval)
762 struct proc *p;
763 struct sem_post_args *uap;
764 register_t *retval;
765 {
766 int fd = (int)uap->sem;
767 register struct filedesc *fdp = p->p_fd;
768 struct file *fp;
769 struct pseminfo * pinfo;
770 struct psemnode * pnode ;
771 kern_return_t kret;
772 int error;
773
774 if (error = fdgetf(p, (int)uap->sem, &fp))
775 return (error);
776 if (fp->f_type != DTYPE_PSXSEM)
777 return(EBADF);
778 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
779 return(EINVAL);
780 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
781 return(EINVAL);
782 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
783 != PSEM_ALLOCATED) {
784 return(EINVAL);
785 }
786
787 kret = semaphore_signal(pinfo->psem_semobject);
788 switch (kret) {
789 case KERN_INVALID_ADDRESS:
790 case KERN_PROTECTION_FAILURE:
791 return (EINVAL);
792 case KERN_ABORTED:
793 case KERN_OPERATION_TIMED_OUT:
794 return (EINTR);
795 case KERN_SUCCESS:
796 return(0);
797 default:
798 return (EINVAL);
799 }
800 }
801
802 struct sem_init_args {
803 sem_t *sem;
804 int phsared;
805 unsigned int value;
806 };
807
808 int
809 sem_init(p, uap, retval)
810 struct proc *p;
811 struct sem_init_args *uap;
812 register_t *retval;
813 {
814 return(ENOSYS);
815 }
816
817 struct sem_destroy_args {
818 sem_t *sem;
819 };
820
821 int
822 sem_destroy(p, uap, retval)
823 struct proc *p;
824 struct sem_destroy_args *uap;
825 register_t *retval;
826 {
827 return(ENOSYS);
828 }
829
830 struct sem_getvalue_args {
831 sem_t *sem;
832 int * sval;
833 };
834
835 int
836 sem_getvalue(p, uap, retval)
837 struct proc *p;
838 struct sem_getvalue_args *uap;
839 register_t *retval;
840 {
841 return(ENOSYS);
842 }
843
844 static int
845 psem_close(pnode, flags, cred, p)
846 register struct psemnode *pnode;
847 int flags;
848 struct ucred *cred;
849 struct proc *p;
850 {
851 int error=0;
852 kern_return_t kret;
853 register struct pseminfo *pinfo;
854
855 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
856 return(EINVAL);
857
858 if ((pinfo->psem_flags & PSEM_ALLOCATED) != PSEM_ALLOCATED) {
859 return(EINVAL);
860 }
861 #if DIAGNOSTIC
862 if(!pinfo->psem_usecount) {
863 kprintf("negative usecount in psem_close\n");
864 }
865 #endif /* DIAGNOSTIC */
866 pinfo->psem_usecount--;
867
868 if ((pinfo->psem_flags & PSEM_REMOVED) && !pinfo->psem_usecount) {
869 error = psem_delete(pinfo);
870 _FREE(pinfo,M_SHM);
871 }
872 _FREE(pnode, M_SHM);
873 return (error);
874 }
875
876 static int
877 psem_closefile(fp, p)
878 struct file *fp;
879 struct proc *p;
880 {
881
882 return (psem_close(((struct psemnode *)fp->f_data), fp->f_flag,
883 fp->f_cred, p));
884 }
885
886 int
887 psem_delete(struct pseminfo * pinfo)
888 {
889 kern_return_t kret;
890
891 kret = semaphore_destroy(kernel_task, pinfo->psem_semobject);
892
893 switch (kret) {
894 case KERN_INVALID_ADDRESS:
895 case KERN_PROTECTION_FAILURE:
896 return (EINVAL);
897 case KERN_ABORTED:
898 case KERN_OPERATION_TIMED_OUT:
899 return (EINTR);
900 case KERN_SUCCESS:
901 return(0);
902 default:
903 return (EINVAL);
904 }
905 }
906
907 static int
908 psem_read(fp, uio, cred, flags, p)
909 struct file *fp;
910 struct uio *uio;
911 struct ucred *cred;
912 int flags;
913 struct proc *p;
914 {
915 return(EOPNOTSUPP);
916 }
917
918 static int
919 psem_write(fp, uio, cred, flags, p)
920 struct file *fp;
921 struct uio *uio;
922 struct ucred *cred;
923 int flags;
924 struct proc *p;
925 {
926 return(EOPNOTSUPP);
927 }
928
929 static int
930 psem_ioctl(fp, com, data, p)
931 struct file *fp;
932 u_long com;
933 caddr_t data;
934 struct proc *p;
935 {
936 return(EOPNOTSUPP);
937 }
938
939 static int
940 psem_select(fp, which, wql, p)
941 struct file *fp;
942 int which;
943 void *wql;
944 struct proc *p;
945 {
946 return(EOPNOTSUPP);
947 }
948
949 static int
950 psem_kqfilter(fp, kn, p)
951 struct file *fp;
952 struct knote *kn;
953 struct proc *p;
954 {
955 return (EOPNOTSUPP);
956 }
957