void linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss) { int b, l; SIGEMPTYSET(*bss); bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); bss->__bits[1] = lss->__bits[1]; for (l = 1; l <= LINUX_SIGTBLSZ; l++) { if (LINUX_SIGISMEMBER(*lss, l)) { b = linux_to_bsd_signal[_SIG_IDX(l)]; if (b) SIGADDSET(*bss, b); } } }
/* * Advise a kernel process to suspend (or resume) in its main loop. * Participation is voluntary. */ int kproc_suspend(struct proc *p, int timo) { /* * Make sure this is indeed a system process and we can safely * use the p_siglist field. */ PROC_LOCK(p); if ((p->p_flag & P_KTHREAD) == 0) { PROC_UNLOCK(p); return (EINVAL); } SIGADDSET(p->p_siglist, SIGSTOP); wakeup(p); return msleep(&p->p_siglist, &p->p_mtx, PPAUSE | PDROP, "suspkp", timo); }
void _pthread_exit_mask(void *status, sigset_t *mask) { struct pthread *curthread = _get_curthread(); /* Check if this thread is already in the process of exiting: */ if (curthread->cancelling) { char msg[128]; snprintf(msg, sizeof(msg), "Thread %p has called " "pthread_exit() from a destructor. POSIX 1003.1 " "1996 s16.2.5.2 does not allow this!", curthread); PANIC(msg); } /* Flag this thread as exiting. */ curthread->cancelling = 1; curthread->no_cancel = 1; curthread->cancel_async = 0; curthread->cancel_point = 0; if (mask != NULL) __sys_sigprocmask(SIG_SETMASK, mask, NULL); if (curthread->unblock_sigcancel) { sigset_t set; curthread->unblock_sigcancel = 0; SIGEMPTYSET(set); SIGADDSET(set, SIGCANCEL); __sys_sigprocmask(SIG_UNBLOCK, mask, NULL); } /* Save the return value: */ curthread->ret = status; #ifdef _PTHREAD_FORCED_UNWIND #ifdef PIC thread_uw_init(); #endif /* PIC */ #ifdef PIC if (uwl_forcedunwind != NULL) { #else if (_Unwind_ForcedUnwind != NULL) { #endif if (curthread->unwind_disabled) { if (message_printed == 0) { message_printed = 1; _thread_printf(2, "Warning: old _pthread_cleanup_push was called, " "stack unwinding is disabled.\n"); } goto cleanup; } thread_unwind(); } else { cleanup: while (curthread->cleanup != NULL) { __pthread_cleanup_pop_imp(1); } exit_thread(); } #else while (curthread->cleanup != NULL) { __pthread_cleanup_pop_imp(1); } exit_thread(); #endif /* _PTHREAD_FORCED_UNWIND */ } static void exit_thread(void) { struct pthread *curthread = _get_curthread(); /* Check if there is thread specific data: */ if (curthread->specific != NULL) { /* Run the thread-specific data destructors: */ _thread_cleanupspecific(); } if (!_thr_isthreaded()) exit(0); if (atomic_fetchadd_int(&_thread_active_threads, -1) == 1) { exit(0); /* Never reach! */ } /* Tell malloc that the thread is exiting. */ _malloc_thread_cleanup(); THR_LOCK(curthread); curthread->state = PS_DEAD; if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { curthread->cycle++; _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); } if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) _thr_report_death(curthread); /* * Thread was created with initial refcount 1, we drop the * reference count to allow it to be garbage collected. */ curthread->refcount--; _thr_try_gc(curthread, curthread); /* thread lock released */ #if defined(_PTHREADS_INVARIANTS) if (THR_IN_CRITICAL(curthread)) PANIC("thread exits with resources held!"); #endif /* * Kernel will do wakeup at the address, so joiner thread * will be resumed if it is sleeping at the address. */ thr_exit(&curthread->tid); PANIC("thr_exit() returned"); /* Never reach! */ }
/* * This is the meat and potatoes of the program. Spawn creates a tree * of processes with Dval depth and Bval breadth. Each parent will spawn * Bval children. Each child will store information about themselves * in shared memory. The leaf nodes will communicate the existence * of one another through message queues, once each leaf node has * received communication from all of her siblings she will reduce * the semaphore count and exit. Meanwhile all parents are waiting * to hear from their children through the use of semaphores. When * the semaphore count reaches zero then the parent knows all the * children have talked to one another. Locking of the connter semaphore * is provided by the use of another (binary) semaphore. */ int spawn(int val) { extern int sem_count; /* used to keep track of childern */ extern int sem_lock; /* used to lock access to sem_count semaphore */ int i; /* Breadth counter */ static int level = 0; /* level counter */ int lvlflg = 0; /* level toggle, limits parental spawning to one generation */ int pslot = 0; #ifdef __64LDT__ pid_t pid; /* pid of child process */ #else int pid; /* pid of child process */ #endif Pinfo *pinfo; /* pointer to process information in shared mem */ int semval; /* value of semaphore ( equals BVAL initially */ static int tval = 1; /* tree node value of child. */ char foo[1024]; level++; for (i = 1; i <= BVAL; i++) { tval = (val * BVAL) + i; if (!lvlflg) { pid = fork(); if (!pid) { /* CHILD */ if (AUSDEBUG) { sprintf(foo, "%sslot%d", SLOTDIR, tval); debugfp = fopen(foo, "a+"); } pinfo = put_proc_info(tval); debugout ("pid: %-6d ppid: %-6d lev: %-2d i: %-2d val: %-3d\n", pinfo->pid, pinfo->ppid, level, i, tval); set_timer(); /* set up signal handlers and initialize pgrp */ if (level < DVAL) { if (spawn(tval) == -1) { pslot = semoper(tval, sem_lock, -1); semarg.val = 0; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ semval = semctl(sem_count, pslot, GETVAL, semarg); semarg.val = --semval; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ semctl(sem_count, pslot, SETVAL, semarg); semarg.val = 1; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ semctl(sem_lock, pslot, SETVAL, semarg); } lvlflg++; } else { /* leaf node */ notify(tval); return (-1); } } #ifdef __64LDT__ else if (pid > 0 && i >= BVAL) { /* PARENT */ #else else if (pid > (pid_t) 0 && i >= BVAL) { /* PARENT */ #endif pslot = semoper(tval, sem_count, 0); pslot = semoper(pslot, sem_lock, -1); semarg.val = 0; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ semval = semctl(sem_count, pslot, GETVAL, semarg); semarg.val = --semval; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ semctl(sem_count, pslot, SETVAL, semarg); semarg.val = 1; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ semctl(sem_lock, pslot, SETVAL, semarg); (shmaddr + val)->msg++; } #ifdef __64LDT__ else if (pid < (pid_t) 0) { #else else if (pid < 0) { #endif perror("spawn: fork failed"); severe ("spawn: fork failed, exiting with errno %d\n", errno); exit(1); } else (shmaddr + val)->msg++; } } return (pslot); } /* * Allocate message queues. */ void setup_msgqueue(void) { extern int msgid; extern int msgerr; msgid = msgget(IPC_PRIVATE, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (msgid == -1) { perror("msgget msgid failed"); fprintf(stderr, " SEVERE : msgget msgid failed: errno %d\n", errno); exit(1); } msgerr = msgget(IPC_PRIVATE, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (msgerr == -1) { perror("msgget msgerr failed"); fprintf(stderr, " SEVERE : msgget msgerr failed: errno %d\n", errno); exit(1); } } /* * Set up and initialize all semaphores */ void setup_semaphores(void) { extern int sem_count; extern int sem_lock; int i; int rc; prtln(); sem_lock = semget(IPC_PRIVATE, nodesum - 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); dprt("nodesum = %d, sem_lock = %d\n", nodesum, sem_lock); prtln(); if (sem_lock == -1) { perror("semget failed for sem_lock"); fprintf(stderr, " SEVERE : semget failed for sem_lock, errno: %d\n", errno); rm_shmseg(); exit(1); } prtln(); sem_count = semget(IPC_PRIVATE, nodesum - 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (sem_count == -1) { perror("semget failed for sem_count"); fprintf(stderr, " SEVERE : semget failed for sem_count, errno: %d\n", errno); rm_shmseg(); exit(1); } prtln(); for (i = 0; i < (nodesum - 1); i++) { semarg.val = 1; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ rc = semctl(sem_lock, i, SETVAL, semarg); prtln(); if (rc == -1) { perror("semctl failed for sem_lock failed"); fprintf(stderr, " SEVERE : semctl failed for sem_lock, errno: %d\n", errno); rm_shmseg(); exit(1); } semarg.val = BVAL; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */ rc = semctl(sem_count, i, SETVAL, semarg); prtln(); if (rc == -1) { perror("semctl failed for sem_lock failed"); fprintf(stderr, " SEVERE : semctl failed for sem_lock, errno: %d\n", errno); rm_shmseg(); exit(1); } } } /* * Set up and allocate shared memory. */ void setup_shm(void) { extern int nodesum; /* global shared memory id */ extern int shmid; /* global shared memory id */ extern Pinfo *shmaddr; int i, j; /* counters */ Pinfo *shmad = NULL; /* ptr to start of shared memory. */ Pinfo *pinfo = NULL; /* ptr to struct in shared memory. */ debugout("size = %d, size (in hex) = %#x nodes: %d\n", sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)), sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)), nodesum); /* Get shared memory id */ shmid = shmget(IPC_PRIVATE, sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)), IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (shmid < 0) { perror("shmget failed"); fprintf(stderr, " SEVERE : shmget failed: errno %d\n", errno); exit(1); } /* allocate shared memory */ if ((shmad = shmat(shmid, (char *)shmad, 0)) == MAP_FAILED) { printf("SEVERE : shmat failed\n"); exit(1); } else { shmctl(shmid, IPC_RMID, NULL); } /* set all fields in shared memory to -1 */ for (pinfo = shmad, i = 0; i < nodesum; i++, pinfo++) { #ifdef __64LDT__ pinfo->pid = (pid_t) - 1; pinfo->ppid = (pid_t) - 1; #else pinfo->pid = -1; pinfo->ppid = -1; #endif pinfo->msg = -1; pinfo->err = -1; /* Changed 10/9/97 */ /* pinfo->list = (int *)((ulong)shmad + nodesum * sizeof(Pinfo) + (sizeof(int) * BVAL * i)); */ pinfo->list = (int *)((long)shmad + nodesum * sizeof(Pinfo) + (sizeof(int) * BVAL * i)); for (j = 0; j < BVAL; j++) *(pinfo->list + j) = -1; } shmaddr = shmad; } /* * Set up Signal handler and which signals to catch */ void set_signals(void *sighandler()) { int i; int rc; struct sigaction action; /* list of signals we want to catch */ static struct signalinfo { int signum; char *signame; } siginfo[] = { { SIGHUP, "SIGHUP"}, { SIGINT, "SIGINT"}, { SIGQUIT, "SIGQUIT"}, { SIGABRT, "SIGABRT"}, { SIGBUS, "SIGBUS"}, { SIGSEGV, "SIGSEGV"}, { SIGALRM, "SIGALRM"}, { SIGUSR1, "SIGUSR1"}, { SIGUSR2, "SIGUSR2"}, { -1, "ENDSIG"} }; char tmpstr[1024]; action.sa_handler = (void *)sighandler; #ifdef _LINUX sigfillset(&action.sa_mask); #else SIGINITSET(action.sa_mask); #endif action.sa_flags = 0; /* Set the signal handler up */ #ifdef _LINUX sigaddset(&action.sa_mask, SIGTERM); #else SIGADDSET(action.sa_mask, SIGTERM); #endif for (i = 0; siginfo[i].signum != -1; i++) { #ifdef _LINUX sigaddset(&action.sa_mask, siginfo[i].signum); #else SIGADDSET(action.sa_mask, siginfo[i].signum); #endif rc = sigaction(siginfo[i].signum, &action, NULL); if (rc == -1) { sprintf(tmpstr, "sigaction: %s\n", siginfo[i].signame); perror(tmpstr); fprintf(stderr, " SEVERE : Could not set %s signal action, errno=%d.", siginfo[i].signame, errno); exit(1); } } }
static void pmclog_loop(void *arg) { struct pmclog_proc_init_args *ia; struct pmc_owner *po; struct pmclog_buffer *lb; struct proc *p; struct ucred *ownercred; struct ucred *mycred; struct thread *td; sigset_t unb; struct uio auio; struct iovec aiov; size_t nbytes; int error; td = curthread; SIGEMPTYSET(unb); SIGADDSET(unb, SIGHUP); (void)kern_sigprocmask(td, SIG_UNBLOCK, &unb, NULL, 0); ia = arg; MPASS(ia->kthr == curproc); MPASS(!ia->acted); mtx_lock(&pmc_kthread_mtx); while (ia->po == NULL && !ia->exit) msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogi", 0); if (ia->exit) { ia->acted = true; wakeup(ia); mtx_unlock(&pmc_kthread_mtx); kproc_exit(0); } MPASS(ia->po != NULL); po = ia->po; ia->acted = true; wakeup(ia); mtx_unlock(&pmc_kthread_mtx); ia = NULL; p = po->po_owner; mycred = td->td_ucred; PROC_LOCK(p); ownercred = crhold(p->p_ucred); PROC_UNLOCK(p); PMCDBG2(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); KASSERT(po->po_kthread == curthread->td_proc, ("[pmclog,%d] proc mismatch po=%p po/kt=%p curproc=%p", __LINE__, po, po->po_kthread, curthread->td_proc)); lb = NULL; /* * Loop waiting for I/O requests to be added to the owner * struct's queue. The loop is exited when the log file * is deconfigured. */ mtx_lock(&pmc_kthread_mtx); for (;;) { /* check if we've been asked to exit */ if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) break; if (lb == NULL) { /* look for a fresh buffer to write */ mtx_lock_spin(&po->po_mtx); if ((lb = TAILQ_FIRST(&po->po_logbuffers)) == NULL) { mtx_unlock_spin(&po->po_mtx); /* No more buffers and shutdown required. */ if (po->po_flags & PMC_PO_SHUTDOWN) break; (void) msleep(po, &pmc_kthread_mtx, PWAIT, "pmcloop", 0); continue; } TAILQ_REMOVE(&po->po_logbuffers, lb, plb_next); mtx_unlock_spin(&po->po_mtx); } mtx_unlock(&pmc_kthread_mtx); /* process the request */ PMCDBG3(LOG,WRI,2, "po=%p base=%p ptr=%p", po, lb->plb_base, lb->plb_ptr); /* change our thread's credentials before issuing the I/O */ aiov.iov_base = lb->plb_base; aiov.iov_len = nbytes = lb->plb_ptr - lb->plb_base; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = -1; auio.uio_resid = nbytes; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_SYSSPACE; auio.uio_td = td; /* switch thread credentials -- see kern_ktrace.c */ td->td_ucred = ownercred; error = fo_write(po->po_file, &auio, ownercred, 0, td); td->td_ucred = mycred; if (error) { /* XXX some errors are recoverable */ /* send a SIGIO to the owner and exit */ PROC_LOCK(p); kern_psignal(p, SIGIO); PROC_UNLOCK(p); mtx_lock(&pmc_kthread_mtx); po->po_error = error; /* save for flush log */ PMCDBG2(LOG,WRI,2, "po=%p error=%d", po, error); break; } mtx_lock(&pmc_kthread_mtx); /* put the used buffer back into the global pool */ PMCLOG_INIT_BUFFER_DESCRIPTOR(lb); mtx_lock_spin(&pmc_bufferlist_mtx); TAILQ_INSERT_HEAD(&pmc_bufferlist, lb, plb_next); mtx_unlock_spin(&pmc_bufferlist_mtx); lb = NULL; } wakeup_one(po->po_kthread); po->po_kthread = NULL; mtx_unlock(&pmc_kthread_mtx); /* return the current I/O buffer to the global pool */ if (lb) { PMCLOG_INIT_BUFFER_DESCRIPTOR(lb); mtx_lock_spin(&pmc_bufferlist_mtx); TAILQ_INSERT_HEAD(&pmc_bufferlist, lb, plb_next); mtx_unlock_spin(&pmc_bufferlist_mtx); } /* * Exit this thread, signalling the waiter */ crfree(ownercred); kproc_exit(0); }