int _sem_wait(sem_t *sem) { struct pthread *curthread; int retval; if (sem_check_validity(sem) != 0) return (-1); curthread = _get_curthread(); if ((*sem)->syssem != 0) { _thr_cancel_enter(curthread); retval = ksem_wait((*sem)->semid); _thr_cancel_leave(curthread, retval != 0); } else { _pthread_testcancel(); _pthread_mutex_lock(&(*sem)->lock); while ((*sem)->count <= 0) { (*sem)->nwaiters++; THR_CLEANUP_PUSH(curthread, decrease_nwaiters, sem); _pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); THR_CLEANUP_POP(curthread, 0); (*sem)->nwaiters--; } (*sem)->count--; _pthread_mutex_unlock(&(*sem)->lock); retval = 0; } return (retval); }
/* * Fork off a child process. The child will open the semaphore via * the same name. The child will then block on the semaphore waiting * for the parent to post it. */ static int wait_twoproc_child(void *arg) { semid_t id; if (ksem_open(&id, TEST_PATH, 0, 0, 0) < 0) return (CSTAT(1, errno)); if (ksem_wait(id) < 0) return (CSTAT(2, errno)); if (ksem_close(id) < 0) return (CSTAT(3, errno)); return (CSTAT(0, 0)); }
static void use_after_unlink_test(void) { semid_t id; /* * Create named semaphore with value of 1 and then unlink it * while still retaining the initial reference. */ if (ksem_open(&id, TEST_PATH, O_CREAT | O_EXCL, 0777, 1) < 0) { fail_errno("ksem_open(O_CREAT | O_EXCL)"); return; } if (ksem_unlink(TEST_PATH) < 0) { fail_errno("ksem_unlink"); ksem_close(id); return; } if (checkvalue(id, 1) < 0) { ksem_close(id); return; } /* Post the semaphore to set its value to 2. */ if (ksem_post(id) < 0) { fail_errno("ksem_post"); ksem_close(id); return; } if (checkvalue(id, 2) < 0) { ksem_close(id); return; } /* Wait on the semaphore which should set its value to 1. */ if (ksem_wait(id) < 0) { fail_errno("ksem_wait"); ksem_close(id); return; } if (checkvalue(id, 1) < 0) { ksem_close(id); return; } if (ksem_close(id) < 0) { fail_errno("ksem_close"); return; } pass(); }
static void wait_invalid_semaphore(void) { if (ksem_wait(STDERR_FILENO) >= 0) { fail_err("ksem_wait() didn't fail"); return; } if (errno != EINVAL) { fail_errno("ksem_wait"); return; } pass(); }
static int testwait(semid_t id, u_int *delta) { struct timespec start, end; if (clock_gettime(CLOCK_REALTIME, &start) < 0) { fail_errno("clock_gettime(CLOCK_REALTIME)"); return (-1); } if (ksem_wait(id) < 0) { fail_errno("ksem_wait"); return (-1); } if (clock_gettime(CLOCK_REALTIME, &end) < 0) { fail_errno("clock_gettime(CLOCK_REALTIME)"); return (-1); } timespecsub(&end, &start); *delta = end.tv_nsec / 1000000; *delta += end.tv_sec * 1000; return (0); }
static void busy_destroy_test(void) { char errbuf[_POSIX2_LINE_MAX]; struct kinfo_proc *kp; semid_t id; pid_t pid; kvm_t *kd; int count; kd = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, errbuf); if (kd == NULL) { fail_err("kvm_openfiles: %s", errbuf); return; } if (ksem_init(&id, 0) < 0) { fail_errno("ksem_init"); kvm_close(kd); return; } pid = fork(); switch (pid) { case -1: /* Error. */ fail_errno("fork"); ksem_destroy(id); kvm_close(kd); return; case 0: /* Child. */ ksem_wait(id); exit(0); } /* * Wait for the child process to block on the semaphore. This * is a bit gross. */ for (;;) { kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &count); if (kp == NULL) { fail_err("kvm_getprocs: %s", kvm_geterr(kd)); kvm_close(kd); ksem_destroy(id); return; } if (kp->ki_stat == SSLEEP && (strcmp(kp->ki_wmesg, "sem") == 0 || strcmp(kp->ki_wmesg, "ksem") == 0)) break; usleep(1000); } kvm_close(kd); ksem_destroy_should_fail(id, EBUSY); /* Cleanup. */ ksem_post(id); waitpid(pid, NULL, 0); ksem_destroy(id); }