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