]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/posix_sem.c
xnu-344.23.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 * 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 #define PSEMNAMLEN 31 /* maximum name segment length we bother with */
63
64 struct pseminfo {
65 unsigned int psem_flags;
66 unsigned int psem_usecount;
67 mode_t psem_mode;
68 uid_t psem_uid;
69 gid_t psem_gid;
70 char psem_name[PSEMNAMLEN + 1]; /* segment name */
71 void * psem_semobject;
72 struct proc * sem_proc;
73 };
74 #define PSEMINFO_NULL (struct pseminfo *)0
75
76 #define PSEM_NONE 1
77 #define PSEM_DEFINED 2
78 #define PSEM_ALLOCATED 4
79 #define PSEM_MAPPED 8
80 #define PSEM_INUSE 0x10
81 #define PSEM_REMOVED 0x20
82 #define PSEM_INCREATE 0x40
83 #define PSEM_INDELETE 0x80
84
85 struct psemcache {
86 LIST_ENTRY(psemcache) psem_hash; /* hash chain */
87 struct pseminfo *pseminfo; /* vnode the name refers to */
88 int psem_nlen; /* length of name */
89 char psem_name[PSEMNAMLEN + 1]; /* segment name */
90 };
91 #define PSEMCACHE_NULL (struct psemcache *)0
92
93 struct psemstats {
94 long goodhits; /* hits that we can really use */
95 long neghits; /* negative hits that we can use */
96 long badhits; /* hits we must drop */
97 long falsehits; /* hits with id mismatch */
98 long miss; /* misses */
99 long longnames; /* long names that ignore cache */
100 };
101
102 struct psemname {
103 char *psem_nameptr; /* pointer to looked up name */
104 long psem_namelen; /* length of looked up component */
105 u_long psem_hash; /* hash value of looked up name */
106 };
107
108 struct psemnode {
109 struct pseminfo *pinfo;
110 #if DIAGNOSTIC
111 unsigned int readcnt;
112 unsigned int writecnt;
113 #endif
114 };
115 #define PSEMNODE_NULL (struct psemnode *)0
116
117
118 #define PSEMHASH(pnp) \
119 (&psemhashtbl[(pnp)->psem_hash & psemhash])
120 LIST_HEAD(psemhashhead, psemcache) *psemhashtbl; /* Hash Table */
121 u_long psemhash; /* size of hash table - 1 */
122 long psemnument; /* number of cache entries allocated */
123 struct psemstats psemstats; /* cache effectiveness statistics */
124
125 static int psem_cache_search __P((struct pseminfo **,
126 struct psemname *, struct psemcache **));
127
128 static int psem_read __P((struct file *fp, struct uio *uio,
129 struct ucred *cred, int flags, struct proc *p));
130 static int psem_write __P((struct file *fp, struct uio *uio,
131 struct ucred *cred, int flags, struct proc *p));
132 static int psem_ioctl __P((struct file *fp, u_long com,
133 caddr_t data, struct proc *p));
134 static int psem_select __P((struct file *fp, int which, void *wql,
135 struct proc *p));
136 static 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 static 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 static 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 static void
260 psem_cache_delete(pcp)
261 struct psemcache *pcp;
262 {
263 #if DIAGNOSTIC
264 if (pcp->psem_hash.le_prev == 0)
265 panic("psem namecache purge le_prev");
266 if (pcp->psem_hash.le_next == pcp)
267 panic("namecache purge le_next");
268 #endif /* DIAGNOSTIC */
269 LIST_REMOVE(pcp, psem_hash);
270 pcp->psem_hash.le_prev = 0;
271 psemnument--;
272 }
273
274 /*
275 * Invalidate a all entries to particular vnode.
276 *
277 * We actually just increment the v_id, that will do it. The entries will
278 * be purged by lookup as they get found. If the v_id wraps around, we
279 * need to ditch the entire cache, to avoid confusion. No valid vnode will
280 * ever have (v_id == 0).
281 */
282 void
283 psem_cache_purge(void)
284 {
285 struct psemcache *pcp;
286 struct psemhashhead *pcpp;
287
288 for (pcpp = &psemhashtbl[psemhash]; pcpp >= psemhashtbl; pcpp--) {
289 while (pcp = pcpp->lh_first)
290 psem_cache_delete(pcp);
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 #ifdef PSXSEM_NAME_RESTRICT
345 nameptr = pnbuf;
346 if (*nameptr == '/') {
347 while (*(nameptr++) == '/') {
348 plen--;
349 error = EINVAL;
350 goto bad;
351 }
352 } else {
353 error = EINVAL;
354 goto bad;
355 }
356 #endif /* PSXSEM_NAME_RESTRICT */
357
358 plen = pathlen;
359 nameptr = pnbuf;
360 nd.psem_nameptr = nameptr;
361 nd.psem_namelen = plen;
362 nd. psem_hash =0;
363
364 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
365 nd.psem_hash += (unsigned char)*cp * i;
366 }
367
368 error = psem_cache_search(&pinfo, &nd, &pcache);
369
370 if (error == ENOENT) {
371 error = EINVAL;
372 goto bad;
373
374 }
375 if (!error) {
376 incache = 0;
377 } else
378 incache = 1;
379 fmode = FFLAGS(uap->oflag);
380
381 if (error = falloc(p, &nfp, &indx)) {
382 goto bad;
383 }
384
385 fp = nfp;
386 cmode &= ALLPERMS;
387
388 if (((fmode & (O_CREAT | O_EXCL))==(O_CREAT | O_EXCL)) && incache) {
389 /* sem exists and opened O_EXCL */
390 #if notyet
391 if (pinfo->psem_flags & PSEM_INDELETE) {
392 }
393 #endif
394 error = EEXIST;
395 goto bad1;
396 }
397 if (((fmode & (O_CREAT | O_EXCL))== O_CREAT) && incache) {
398 /* As per POSIX, O_CREAT has no effect */
399 fmode &= ~O_CREAT;
400 }
401
402 if (fmode & O_CREAT) {
403 if((value < 0) && (value > SEM_VALUE_MAX)) {
404 error = EINVAL;
405 goto bad1;
406 }
407 pinfo = (struct pseminfo *)_MALLOC(sizeof(struct pseminfo), M_SHM, M_WAITOK);
408 bzero(pinfo, sizeof(struct pseminfo));
409 pinfo_alloc = 1;
410 pinfo->psem_flags = PSEM_DEFINED | PSEM_INCREATE;
411 pinfo->psem_usecount = 1;
412 pinfo->psem_mode = cmode;
413 pinfo->psem_uid = p->p_ucred->cr_uid;
414 pinfo->psem_gid = p->p_ucred->cr_gid;
415 kret = semaphore_create(kernel_task, &pinfo->psem_semobject,
416 SYNC_POLICY_FIFO, value);
417 if(kret != KERN_SUCCESS)
418 goto bad3;
419 pinfo->psem_flags &= ~PSEM_DEFINED;
420 pinfo->psem_flags |= PSEM_ALLOCATED;
421 pinfo->sem_proc = p;
422 } else {
423 /* semaphore should exist as it is without O_CREAT */
424 if (!incache) {
425 error = ENOENT;
426 goto bad1;
427 }
428 if( pinfo->psem_flags & PSEM_INDELETE) {
429 error = ENOENT;
430 goto bad1;
431 }
432 if (error = psem_access(pinfo, fmode, p->p_ucred, p))
433 goto bad1;
434 }
435 pnode = (struct psemnode *)_MALLOC(sizeof(struct psemnode), M_SHM, M_WAITOK);
436 bzero(pnode, sizeof(struct psemnode));
437
438 if (!incache) {
439 if (error = psem_cache_add(pinfo, &nd)) {
440 goto bad2;
441 }
442 }
443 pinfo->psem_flags &= ~PSEM_INCREATE;
444 pinfo->psem_usecount++;
445 pnode->pinfo = pinfo;
446 fp->f_flag = flags & FMASK;
447 fp->f_type = DTYPE_PSXSEM;
448 fp->f_ops = &psemops;
449 fp->f_data = (caddr_t)pnode;
450 *fdflags(p, indx) &= ~UF_RESERVED;
451 *retval = indx;
452 _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
453 return (0);
454
455 bad3:
456 switch (kret) {
457 case KERN_RESOURCE_SHORTAGE:
458 error = ENOMEM;
459 case KERN_PROTECTION_FAILURE:
460 error = EACCES;
461 default:
462 error = EINVAL;
463 }
464 goto bad1;
465 bad2:
466 _FREE(pnode, M_SHM);
467 if (pinfo_alloc)
468 _FREE(pinfo, M_SHM);
469 bad1:
470 fdrelse(p, indx);
471 ffree(nfp);
472 bad:
473 _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
474 return (error);
475 }
476
477 int
478 psem_access(pinfo, mode, cred, p)
479 struct pseminfo *pinfo;
480 int mode;
481 struct ucred *cred;
482 struct proc *p;
483 {
484 mode_t mask;
485 register gid_t *gp;
486 int i, error;
487
488 /* Otherwise, user id 0 always gets access. */
489 if (cred->cr_uid == 0)
490 return (0);
491
492 mask = 0;
493
494 /* Otherwise, check the owner. */
495 if (cred->cr_uid == pinfo->psem_uid) {
496 if (mode & FREAD)
497 mask |= S_IRUSR;
498 if (mode & FWRITE)
499 mask |= S_IWUSR;
500 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
501 }
502
503 /* Otherwise, check the groups. */
504 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
505 if (pinfo->psem_gid == *gp) {
506 if (mode & FREAD)
507 mask |= S_IRGRP;
508 if (mode & FWRITE)
509 mask |= S_IWGRP;
510 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
511 }
512
513 /* Otherwise, check everyone else. */
514 if (mode & FREAD)
515 mask |= S_IROTH;
516 if (mode & FWRITE)
517 mask |= S_IWOTH;
518 return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES);
519 }
520
521 struct sem_unlink_args {
522 const char *name;
523 };
524
525 int
526 sem_unlink(p, uap, retval)
527 struct proc *p;
528 register struct sem_unlink_args *uap;
529 register_t *retval;
530 {
531 register struct filedesc *fdp = p->p_fd;
532 register struct file *fp;
533 int flags, i;
534 int error=0;
535 struct psemname nd;
536 struct pseminfo *pinfo;
537 extern struct fileops psemops;
538 char * pnbuf;
539 char * nameptr;
540 char * cp;
541 size_t pathlen, plen;
542 int fmode, cmode ;
543 int incache = 0;
544 struct psemnode * pnode = PSEMNODE_NULL;
545 struct psemcache *pcache = PSEMCACHE_NULL;
546 kern_return_t kret;
547
548 pinfo = PSEMINFO_NULL;
549
550 MALLOC_ZONE(pnbuf, caddr_t,
551 MAXPATHLEN, M_NAMEI, M_WAITOK);
552 pathlen = MAXPATHLEN;
553 error = copyinstr(uap->name, pnbuf,
554 MAXPATHLEN, &pathlen);
555 if (error) {
556 goto bad;
557 }
558 if (pathlen > PSEMNAMLEN) {
559 error = ENAMETOOLONG;
560 goto bad;
561 }
562
563
564 #ifdef PSXSEM_NAME_RESTRICT
565 nameptr = pnbuf;
566 if (*nameptr == '/') {
567 while (*(nameptr++) == '/') {
568 plen--;
569 error = EINVAL;
570 goto bad;
571 }
572 } else {
573 error = EINVAL;
574 goto bad;
575 }
576 #endif /* PSXSEM_NAME_RESTRICT */
577
578 plen = pathlen;
579 nameptr = pnbuf;
580 nd.psem_nameptr = nameptr;
581 nd.psem_namelen = plen;
582 nd. psem_hash =0;
583
584 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
585 nd.psem_hash += (unsigned char)*cp * i;
586 }
587
588 error = psem_cache_search(&pinfo, &nd, &pcache);
589
590 if (error == ENOENT) {
591 error = EINVAL;
592 goto bad;
593
594 }
595 if (!error) {
596 error = EINVAL;
597 goto bad;
598 } else
599 incache = 1;
600 if (error = psem_access(pinfo, pinfo->psem_mode, p->p_ucred, p))
601 goto bad;
602
603 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))==0) {
604 return (EINVAL);
605 }
606
607 if (pinfo->psem_flags & PSEM_INDELETE) {
608 error = 0;
609 goto bad;
610 }
611 pinfo->psem_flags |= PSEM_INDELETE;
612 pinfo->psem_usecount--;
613
614 if (!pinfo->psem_usecount) {
615 psem_delete(pinfo);
616 _FREE(pinfo,M_SHM);
617 } else
618 pinfo->psem_flags |= PSEM_REMOVED;
619
620 psem_cache_delete(pcache);
621 _FREE(pcache, M_SHM);
622 error = 0;
623 bad:
624 _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
625 return (error);
626 }
627
628 struct sem_close_args {
629 sem_t *sem;
630 };
631
632 int
633 sem_close(p, uap, retval)
634 struct proc *p;
635 struct sem_close_args *uap;
636 register_t *retval;
637 {
638 int fd = (int)uap->sem;
639 register struct filedesc *fdp = p->p_fd;
640 register struct file *fp;
641 int error = 0;
642
643
644 if ((u_int)fd >= fdp->fd_nfiles ||
645 (fp = fdp->fd_ofiles[fd]) == NULL ||
646 (fdp->fd_ofileflags[fd] & UF_RESERVED))
647 return (EBADF);
648 fdrelse(p, fd);
649 if( error = closef(fp, p))
650 return(error);
651 return(0);
652 }
653
654 struct sem_wait_args {
655 sem_t *sem;
656 };
657
658 int
659 sem_wait(p, uap, retval)
660 struct proc *p;
661 struct sem_wait_args *uap;
662 register_t *retval;
663 {
664 int fd = (int)uap->sem;
665 register struct filedesc *fdp = p->p_fd;
666 struct file *fp;
667 struct pseminfo * pinfo;
668 struct psemnode * pnode ;
669 kern_return_t kret;
670 int error;
671
672 if (error = fdgetf(p, (int)uap->sem, &fp))
673 return (error);
674 if (fp->f_type != DTYPE_PSXSEM)
675 return(EBADF);
676 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
677 return(EINVAL);
678 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
679 return(EINVAL);
680 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
681 != PSEM_ALLOCATED) {
682 return(EINVAL);
683 }
684
685 kret = semaphore_wait(pinfo->psem_semobject);
686 switch (kret) {
687 case KERN_INVALID_ADDRESS:
688 case KERN_PROTECTION_FAILURE:
689 return (EACCES);
690 case KERN_ABORTED:
691 case KERN_OPERATION_TIMED_OUT:
692 return (EINTR);
693 case KERN_SUCCESS:
694 return(0);
695 default:
696 return (EINVAL);
697 }
698 }
699
700 struct sem_trywait_args {
701 sem_t *sem;
702 };
703
704 int
705 sem_trywait(p, uap, retval)
706 struct proc *p;
707 struct sem_trywait_args *uap;
708 register_t *retval;
709 {
710 int fd = (int)uap->sem;
711 register struct filedesc *fdp = p->p_fd;
712 struct file *fp;
713 struct pseminfo * pinfo;
714 struct psemnode * pnode ;
715 kern_return_t kret;
716 mach_timespec_t wait_time;
717 int error;
718
719 if (error = fdgetf(p, (int)uap->sem, &fp))
720 return (error);
721 if (fp->f_type != DTYPE_PSXSEM)
722 return(EBADF);
723 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
724 return(EINVAL);
725 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
726 return(EINVAL);
727 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
728 != PSEM_ALLOCATED) {
729 return(EINVAL);
730 }
731
732 wait_time.tv_sec = 0;
733 wait_time.tv_nsec = 0;
734
735 kret = semaphore_timedwait(pinfo->psem_semobject, MACH_TIMESPEC_ZERO);
736 switch (kret) {
737 case KERN_INVALID_ADDRESS:
738 case KERN_PROTECTION_FAILURE:
739 return (EINVAL);
740 case KERN_ABORTED:
741 return (EINTR);
742 case KERN_OPERATION_TIMED_OUT:
743 return (EAGAIN);
744 case KERN_SUCCESS:
745 return(0);
746 default:
747 return (EINVAL);
748 }
749 }
750
751 struct sem_post_args {
752 sem_t *sem;
753 };
754
755 int
756 sem_post(p, uap, retval)
757 struct proc *p;
758 struct sem_post_args *uap;
759 register_t *retval;
760 {
761 int fd = (int)uap->sem;
762 register struct filedesc *fdp = p->p_fd;
763 struct file *fp;
764 struct pseminfo * pinfo;
765 struct psemnode * pnode ;
766 kern_return_t kret;
767 int error;
768
769 if (error = fdgetf(p, (int)uap->sem, &fp))
770 return (error);
771 if (fp->f_type != DTYPE_PSXSEM)
772 return(EBADF);
773 if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL )
774 return(EINVAL);
775 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
776 return(EINVAL);
777 if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))
778 != PSEM_ALLOCATED) {
779 return(EINVAL);
780 }
781
782 kret = semaphore_signal(pinfo->psem_semobject);
783 switch (kret) {
784 case KERN_INVALID_ADDRESS:
785 case KERN_PROTECTION_FAILURE:
786 return (EINVAL);
787 case KERN_ABORTED:
788 case KERN_OPERATION_TIMED_OUT:
789 return (EINTR);
790 case KERN_SUCCESS:
791 return(0);
792 default:
793 return (EINVAL);
794 }
795 }
796
797 struct sem_init_args {
798 sem_t *sem;
799 int phsared;
800 unsigned int value;
801 };
802
803 int
804 sem_init(p, uap, retval)
805 struct proc *p;
806 struct sem_init_args *uap;
807 register_t *retval;
808 {
809 return(ENOSYS);
810 }
811
812 struct sem_destroy_args {
813 sem_t *sem;
814 };
815
816 int
817 sem_destroy(p, uap, retval)
818 struct proc *p;
819 struct sem_destroy_args *uap;
820 register_t *retval;
821 {
822 return(ENOSYS);
823 }
824
825 struct sem_getvalue_args {
826 sem_t *sem;
827 int * sval;
828 };
829
830 int
831 sem_getvalue(p, uap, retval)
832 struct proc *p;
833 struct sem_getvalue_args *uap;
834 register_t *retval;
835 {
836 return(ENOSYS);
837 }
838
839 static int
840 psem_close(pnode, flags, cred, p)
841 register struct psemnode *pnode;
842 int flags;
843 struct ucred *cred;
844 struct proc *p;
845 {
846 int error=0;
847 kern_return_t kret;
848 register struct pseminfo *pinfo;
849
850 if ((pinfo = pnode->pinfo) == PSEMINFO_NULL)
851 return(EINVAL);
852
853 if ((pinfo->psem_flags & PSEM_ALLOCATED) != PSEM_ALLOCATED) {
854 return(EINVAL);
855 }
856 #if DIAGNOSTIC
857 if(!pinfo->psem_usecount) {
858 kprintf("negative usecount in psem_close\n");
859 }
860 #endif /* DIAGNOSTIC */
861 pinfo->psem_usecount--;
862
863 if ((pinfo->psem_flags & PSEM_REMOVED) && !pinfo->psem_usecount) {
864 error = psem_delete(pinfo);
865 _FREE(pinfo,M_SHM);
866 }
867 _FREE(pnode, M_SHM);
868 return (error);
869 }
870
871 static int
872 psem_closefile(fp, p)
873 struct file *fp;
874 struct proc *p;
875 {
876
877 return (psem_close(((struct psemnode *)fp->f_data), fp->f_flag,
878 fp->f_cred, p));
879 }
880
881 int
882 psem_delete(struct pseminfo * pinfo)
883 {
884 kern_return_t kret;
885
886 kret = semaphore_destroy(kernel_task, pinfo->psem_semobject);
887
888 switch (kret) {
889 case KERN_INVALID_ADDRESS:
890 case KERN_PROTECTION_FAILURE:
891 return (EINVAL);
892 case KERN_ABORTED:
893 case KERN_OPERATION_TIMED_OUT:
894 return (EINTR);
895 case KERN_SUCCESS:
896 return(0);
897 default:
898 return (EINVAL);
899 }
900 }
901
902 static int
903 psem_read(fp, uio, cred, flags, p)
904 struct file *fp;
905 struct uio *uio;
906 struct ucred *cred;
907 int flags;
908 struct proc *p;
909 {
910 return(EOPNOTSUPP);
911 }
912
913 static int
914 psem_write(fp, uio, cred, flags, p)
915 struct file *fp;
916 struct uio *uio;
917 struct ucred *cred;
918 int flags;
919 struct proc *p;
920 {
921 return(EOPNOTSUPP);
922 }
923
924 static int
925 psem_ioctl(fp, com, data, p)
926 struct file *fp;
927 u_long com;
928 caddr_t data;
929 struct proc *p;
930 {
931 return(EOPNOTSUPP);
932 }
933
934 static int
935 psem_select(fp, which, wql, p)
936 struct file *fp;
937 int which;
938 void *wql;
939 struct proc *p;
940 {
941 return(EOPNOTSUPP);
942 }