]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/posix_sem.c
xnu-201.14.tar.gz
[apple/xnu.git] / bsd / kern / posix_sem.c
CommitLineData
1c79356b
A
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
65struct 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
86struct 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
94struct 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
103struct 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
109struct 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])
121LIST_HEAD(psemhashhead, psemcache) *psemhashtbl; /* Hash Table */
122u_long psemhash; /* size of hash table - 1 */
123long psemnument; /* number of cache entries allocated */
124struct psemstats psemstats; /* cache effectiveness statistics */
125
126int psem_cache_search __P((struct pseminfo **, struct psemname *, struct psemcache **));
127
128int psem_read __P((struct file *fp, struct uio *uio,
129 struct ucred *cred));
130int psem_write __P((struct file *fp, struct uio *uio,
131 struct ucred *cred));
132int psem_ioctl __P((struct file *fp, u_long com,
133 caddr_t data, struct proc *p));
134int psem_select __P((struct file *fp, int which,
135 struct proc *p));
136int psem_closefile __P((struct file *fp, struct proc *p));
137
138struct 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
151int
152psem_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 */
198int
199psem_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 */
253void
254psem_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 */
267void
268psem_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
279psem_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
294struct sem_open_args {
295const char *name;
296int oflag;
297int mode;
298int value;
299};
300
301int
302sem_open(p, uap, retval)
303struct proc *p;
304register struct sem_open_args *uap;
305register_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
456bad3:
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;
466bad2:
467 _FREE(pnode, M_SHM);
468 if (pinfo_alloc)
469 _FREE(pinfo, M_SHM);
470bad1:
471 fdrelse(p, indx);
472 ffree(nfp);
473bad:
474 _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
475 return (error);
476}
477
478
479
480int
481psem_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
523struct sem_unlink_args {
524const char *name;
525};
526
527int
528sem_unlink(p, uap, retval)
529struct proc *p;
530register struct sem_unlink_args *uap;
531register_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;
625bad:
626 _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
627 return (error);
628}
629
630struct sem_close_args {
631sem_t *sem;
632};
633
634int
635sem_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
658struct sem_wait_args {
659sem_t *sem;
660};
661
662int
663sem_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
705struct sem_trywait_args {
706sem_t *sem;
707};
708
709int
710sem_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
757struct sem_post_args {
758sem_t *sem;
759};
760
761int
762sem_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
804struct sem_init_args {
805sem_t *sem;
806int phsared;
807unsigned int value;
808};
809
810int
811sem_init(p, uap, retval)
812 struct proc *p;
813 struct sem_init_args *uap;
814 register_t *retval;
815{
816 return(ENOSYS);
817}
818
819struct sem_destroy_args {
820sem_t *sem;
821};
822
823int
824sem_destroy(p, uap, retval)
825 struct proc *p;
826 struct sem_destroy_args *uap;
827 register_t *retval;
828{
829 return(ENOSYS);
830}
831
832struct sem_getvalue_args {
833sem_t *sem;
834int * sval;
835};
836
837int
838sem_getvalue(p, uap, retval)
839 struct proc *p;
840 struct sem_getvalue_args *uap;
841 register_t *retval;
842{
843 return(ENOSYS);
844}
845
846int
847psem_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
857int
858psem_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
889int
890psem_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
912int
913psem_read(struct file *fp, struct uio *uio, struct ucred *cred)
914{
915 return(EOPNOTSUPP);
916}
917int
918psem_write(struct file *fp, struct uio *uio, struct ucred *cred)
919{
920 return(EOPNOTSUPP);
921}
922int
923psem_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
924{
925 return(EOPNOTSUPP);
926}
927int
928psem_select(struct file *fp, int which, struct proc *p)
929{
930 return(EOPNOTSUPP);
931}