/* * This creates a new process as a copy of the old one, * but does not actually start it yet. * * It copies the registers, and all the appropriate * parts of the process environment (as per the clone * flags). The actual kick-off is left to the caller. */ static task_t *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr, int pid) { int retval; struct task_struct *p = NULL; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. */ if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND)) return ERR_PTR(-EINVAL); /* * Shared signal handlers imply shared VM. By way of the above, * thread groups also imply shared VM. Blocking this case allows * for various simplifications in other code. */ if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM)) return ERR_PTR(-EINVAL); retval = security_task_create(clone_flags); if (retval) goto fork_out; retval = -ENOMEM; p = dup_task_struct(current); if (!p) goto fork_out; retval = -EAGAIN; if (atomic_read(&p->user->processes) >= p->signal->rlim[RLIMIT_NPROC].rlim_cur) { if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && p->user != &root_user) goto bad_fork_free; } atomic_inc(&p->user->__count); atomic_inc(&p->user->processes); get_group_info(p->group_info); /* * If multiple threads are within copy_process(), then this check * triggers too late. This doesn't hurt, the check is only there * to stop root fork bombs. */ if (nr_threads >= max_threads) goto bad_fork_cleanup_count; if (!try_module_get(p->thread_info->exec_domain->module)) goto bad_fork_cleanup_count; if (p->binfmt && !try_module_get(p->binfmt->module)) goto bad_fork_cleanup_put_domain; p->did_exec = 0; copy_flags(clone_flags, p); p->pid = pid; retval = -EFAULT; if (clone_flags & CLONE_PARENT_SETTID) if (put_user(p->pid, parent_tidptr)) goto bad_fork_cleanup; p->proc_dentry = NULL; INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); spin_lock_init(&p->proc_lock); clear_tsk_thread_flag(p, TIF_SIGPENDING); init_sigpending(&p->pending); p->utime = cputime_zero; p->stime = cputime_zero; p->sched_time = 0; p->rchar = 0; /* I/O counter: bytes read */ p->wchar = 0; /* I/O counter: bytes written */ p->syscr = 0; /* I/O counter: read syscalls */ p->syscw = 0; /* I/O counter: write syscalls */ acct_clear_integrals(p); p->it_virt_expires = cputime_zero; p->it_prof_expires = cputime_zero; p->it_sched_expires = 0; INIT_LIST_HEAD(&p->cpu_timers[0]); INIT_LIST_HEAD(&p->cpu_timers[1]); INIT_LIST_HEAD(&p->cpu_timers[2]); p->lock_depth = -1; /* -1 = no lock */ do_posix_clock_monotonic_gettime(&p->start_time); p->security = NULL; p->io_context = NULL; p->io_wait = NULL; p->audit_context = NULL; #ifdef CONFIG_NUMA p->mempolicy = mpol_copy(p->mempolicy); if (IS_ERR(p->mempolicy)) { retval = PTR_ERR(p->mempolicy); p->mempolicy = NULL; goto bad_fork_cleanup; } #endif p->tgid = p->pid; if (clone_flags & CLONE_THREAD) p->tgid = current->tgid; if ((retval = security_task_alloc(p))) goto bad_fork_cleanup_policy; if ((retval = audit_alloc(p))) goto bad_fork_cleanup_security; /* copy all the process information */ if ((retval = copy_semundo(clone_flags, p))) goto bad_fork_cleanup_audit; if ((retval = copy_files(clone_flags, p))) goto bad_fork_cleanup_semundo; if ((retval = copy_fs(clone_flags, p))) goto bad_fork_cleanup_files; if ((retval = copy_sighand(clone_flags, p))) goto bad_fork_cleanup_fs; if ((retval = copy_signal(clone_flags, p))) goto bad_fork_cleanup_sighand; if ((retval = copy_mm(clone_flags, p))) goto bad_fork_cleanup_signal; if ((retval = copy_keys(clone_flags, p))) goto bad_fork_cleanup_mm; if ((retval = copy_namespace(clone_flags, p))) goto bad_fork_cleanup_keys; retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) goto bad_fork_cleanup_namespace; p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; /* * Clear TID on mm_release()? */ p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL; /* * Syscall tracing should be turned off in the child regardless * of CLONE_PTRACE. */ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); /* Our parent execution domain becomes current domain These must match for thread signalling to apply */ p->parent_exec_id = p->self_exec_id; /* ok, now we should be set up.. */ p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); p->pdeath_signal = 0; p->exit_state = 0; /* Perform scheduler related setup */ sched_fork(p); /* * Ok, make it visible to the rest of the system. * We dont wake it up yet. */ p->group_leader = p; INIT_LIST_HEAD(&p->ptrace_children); INIT_LIST_HEAD(&p->ptrace_list); /* Need tasklist lock for parent etc handling! */ write_lock_irq(&tasklist_lock); /* * The task hasn't been attached yet, so cpus_allowed mask cannot * have changed. The cpus_allowed mask of the parent may have * changed after it was copied first time, and it may then move to * another CPU - so we re-copy it here and set the child's CPU to * the parent's CPU. This avoids alot of nasty races. */ p->cpus_allowed = current->cpus_allowed; set_task_cpu(p, smp_processor_id()); /* * Check for pending SIGKILL! The new thread should not be allowed * to slip out of an OOM kill. (or normal SIGKILL.) */ if (sigismember(¤t->pending.signal, SIGKILL)) { write_unlock_irq(&tasklist_lock); retval = -EINTR; goto bad_fork_cleanup_namespace; } /* CLONE_PARENT re-uses the old parent */ if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) p->real_parent = current->real_parent; else p->real_parent = current; p->parent = p->real_parent; if (clone_flags & CLONE_THREAD) { spin_lock(¤t->sighand->siglock); /* * Important: if an exit-all has been started then * do not create this new thread - the whole thread * group is supposed to exit anyway. */ if (current->signal->flags & SIGNAL_GROUP_EXIT) { spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); retval = -EAGAIN; goto bad_fork_cleanup_namespace; } p->group_leader = current->group_leader; if (current->signal->group_stop_count > 0) { /* * There is an all-stop in progress for the group. * We ourselves will stop as soon as we check signals. * Make the new thread part of that group stop too. */ current->signal->group_stop_count++; set_tsk_thread_flag(p, TIF_SIGPENDING); } if (!cputime_eq(current->signal->it_virt_expires, cputime_zero) || !cputime_eq(current->signal->it_prof_expires, cputime_zero) || current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY || !list_empty(¤t->signal->cpu_timers[0]) || !list_empty(¤t->signal->cpu_timers[1]) || !list_empty(¤t->signal->cpu_timers[2])) { /* * Have child wake up on its first tick to check * for process CPU timers. */ p->it_prof_expires = jiffies_to_cputime(1); } spin_unlock(¤t->sighand->siglock); } SET_LINKS(p); if (unlikely(p->ptrace & PT_PTRACED)) __ptrace_link(p, current->parent); cpuset_fork(p); attach_pid(p, PIDTYPE_PID, p->pid); attach_pid(p, PIDTYPE_TGID, p->tgid); if (thread_group_leader(p)) { attach_pid(p, PIDTYPE_PGID, process_group(p)); attach_pid(p, PIDTYPE_SID, p->signal->session); if (p->pid) __get_cpu_var(process_counts)++; } nr_threads++; total_forks++; write_unlock_irq(&tasklist_lock); retval = 0; fork_out: if (retval) return ERR_PTR(retval); return p; bad_fork_cleanup_namespace: exit_namespace(p); bad_fork_cleanup_keys: exit_keys(p); bad_fork_cleanup_mm: if (p->mm) mmput(p->mm); bad_fork_cleanup_signal: exit_signal(p); bad_fork_cleanup_sighand: exit_sighand(p); bad_fork_cleanup_fs: exit_fs(p); /* blocking */ bad_fork_cleanup_files: exit_files(p); /* blocking */ bad_fork_cleanup_semundo: exit_sem(p); bad_fork_cleanup_audit: audit_free(p); bad_fork_cleanup_security: security_task_free(p); bad_fork_cleanup_policy: #ifdef CONFIG_NUMA mpol_free(p->mempolicy); #endif bad_fork_cleanup: if (p->binfmt) module_put(p->binfmt->module); bad_fork_cleanup_put_domain: module_put(p->thread_info->exec_domain->module); bad_fork_cleanup_count: put_group_info(p->group_info); atomic_dec(&p->user->processes); free_uid(p->user); bad_fork_free: free_task(p); goto fork_out; }
static void tstp(int dummy GCC_UNUSED) { sigset_t mask, omask; sigaction_t act, oact; #ifdef SIGTTOU int sigttou_blocked; #endif T(("tstp() called")); /* * The user may have changed the prog_mode tty bits, so save them. * * But first try to detect whether we still are in the foreground * process group - if not, an interactive shell may already have * taken ownership of the tty and modified the settings when our * parent was stopped before us, and we would likely pick up the * settings already modified by the shell. */ if (SP != 0 && !SP->_endwin) /* don't do this if we're not in curses */ #if HAVE_TCGETPGRP if (tcgetpgrp(STDIN_FILENO) == getpgrp()) #endif def_prog_mode(); /* * Block window change and timer signals. The latter * is because applications use timers to decide when * to repaint the screen. */ (void) sigemptyset(&mask); (void) sigaddset(&mask, SIGALRM); #if USE_SIGWINCH (void) sigaddset(&mask, SIGWINCH); #endif (void) sigprocmask(SIG_BLOCK, &mask, &omask); #ifdef SIGTTOU sigttou_blocked = sigismember(&omask, SIGTTOU); if (!sigttou_blocked) { (void) sigemptyset(&mask); (void) sigaddset(&mask, SIGTTOU); (void) sigprocmask(SIG_BLOCK, &mask, NULL); } #endif /* * End window mode, which also resets the terminal state to the * original (pre-curses) modes. */ endwin(); /* Unblock SIGTSTP. */ (void) sigemptyset(&mask); (void) sigaddset(&mask, SIGTSTP); #ifdef SIGTTOU if (!sigttou_blocked) { /* Unblock this too if it wasn't blocked on entry */ (void) sigaddset(&mask, SIGTTOU); } #endif (void) sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Now we want to resend SIGSTP to this process and suspend it */ act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = 0; #ifdef SA_RESTART act.sa_flags |= SA_RESTART; #endif /* SA_RESTART */ sigaction(SIGTSTP, &act, &oact); kill(getpid(), SIGTSTP); /* Process gets suspended...time passes...process resumes */ T(("SIGCONT received")); sigaction(SIGTSTP, &oact, NULL); flushinp(); /* * If the user modified the tty state while suspended, he wants * those changes to stick. So save the new "default" terminal state. */ def_shell_mode(); /* * This relies on the fact that doupdate() will restore the * program-mode tty state, and issue enter_ca_mode if need be. */ doupdate(); /* Reset the signals. */ (void) sigprocmask(SIG_SETMASK, &omask, NULL); }
/* * Look whether some events already occurred (or failed) and move * corresponding threads from waiting queue back to ready queue. */ intern void pth_sched_eventmanager(pth_time_t *now, int dopoll) { pth_t nexttimer_thread; pth_event_t nexttimer_ev; pth_time_t nexttimer_value; pth_event_t evh; pth_event_t ev; pth_t t; pth_t tlast; int this_occurred; int any_occurred; fd_set rfds; fd_set wfds; fd_set efds; struct timeval delay; struct timeval *pdelay; sigset_t oss; struct sigaction sa; struct sigaction osa[1+PTH_NSIG]; char minibuf[128]; int loop_repeat; int fdmax; int rc; int sig; int n; pth_debug2("pth_sched_eventmanager: enter in %s mode", dopoll ? "polling" : "waiting"); /* entry point for internal looping in event handling */ loop_entry: loop_repeat = FALSE; /* initialize fd sets */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); fdmax = -1; /* initialize signal status */ sigpending(&pth_sigpending); sigfillset(&pth_sigblock); sigemptyset(&pth_sigcatch); sigemptyset(&pth_sigraised); /* initialize next timer */ pth_time_set(&nexttimer_value, PTH_TIME_ZERO); nexttimer_thread = NULL; nexttimer_ev = NULL; /* for all threads in the waiting queue... */ any_occurred = FALSE; for (t = pth_pqueue_head(&pth_WQ); t != NULL; t = pth_pqueue_walk(&pth_WQ, t, PTH_WALK_NEXT)) { /* determine signals we block */ for (sig = 1; sig < PTH_NSIG; sig++) if (!sigismember(&(t->mctx.sigs), sig)) sigdelset(&pth_sigblock, sig); /* cancellation support */ if (t->cancelreq == TRUE) any_occurred = TRUE; /* ... and all their events... */ if (t->events == NULL) continue; /* ...check whether events occurred */ ev = evh = t->events; do { if (ev->ev_status == PTH_STATUS_PENDING) { this_occurred = FALSE; /* Filedescriptor I/O */ if (ev->ev_type == PTH_EVENT_FD) { /* filedescriptors are checked later all at once. Here we only assemble them in the fd sets */ if (ev->ev_goal & PTH_UNTIL_FD_READABLE) FD_SET(ev->ev_args.FD.fd, &rfds); if (ev->ev_goal & PTH_UNTIL_FD_WRITEABLE) FD_SET(ev->ev_args.FD.fd, &wfds); if (ev->ev_goal & PTH_UNTIL_FD_EXCEPTION) FD_SET(ev->ev_args.FD.fd, &efds); if (fdmax < ev->ev_args.FD.fd) fdmax = ev->ev_args.FD.fd; } /* Filedescriptor Set Select I/O */ else if (ev->ev_type == PTH_EVENT_SELECT) { /* filedescriptors are checked later all at once. Here we only merge the fd sets. */ pth_util_fds_merge(ev->ev_args.SELECT.nfd, ev->ev_args.SELECT.rfds, &rfds, ev->ev_args.SELECT.wfds, &wfds, ev->ev_args.SELECT.efds, &efds); if (fdmax < ev->ev_args.SELECT.nfd-1) fdmax = ev->ev_args.SELECT.nfd-1; } /* Signal Set */ else if (ev->ev_type == PTH_EVENT_SIGS) { for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(ev->ev_args.SIGS.sigs, sig)) { /* thread signal handling */ if (sigismember(&t->sigpending, sig)) { *(ev->ev_args.SIGS.sig) = sig; sigdelset(&t->sigpending, sig); t->sigpendcnt--; this_occurred = TRUE; } /* process signal handling */ if (sigismember(&pth_sigpending, sig)) { if (ev->ev_args.SIGS.sig != NULL) *(ev->ev_args.SIGS.sig) = sig; pth_util_sigdelete(sig); sigdelset(&pth_sigpending, sig); this_occurred = TRUE; } else { sigdelset(&pth_sigblock, sig); sigaddset(&pth_sigcatch, sig); } } } } /* Timer */ else if (ev->ev_type == PTH_EVENT_TIME) { if (pth_time_cmp(&(ev->ev_args.TIME.tv), now) < 0) this_occurred = TRUE; else { /* remember the timer which will be elapsed next */ if ((nexttimer_thread == NULL && nexttimer_ev == NULL) || pth_time_cmp(&(ev->ev_args.TIME.tv), &nexttimer_value) < 0) { nexttimer_thread = t; nexttimer_ev = ev; pth_time_set(&nexttimer_value, &(ev->ev_args.TIME.tv)); } } } /* Message Port Arrivals */ else if (ev->ev_type == PTH_EVENT_MSG) { if (pth_ring_elements(&(ev->ev_args.MSG.mp->mp_queue)) > 0) this_occurred = TRUE; } /* Mutex Release */ else if (ev->ev_type == PTH_EVENT_MUTEX) { if (!(ev->ev_args.MUTEX.mutex->mx_state & PTH_MUTEX_LOCKED)) this_occurred = TRUE; } /* Condition Variable Signal */ else if (ev->ev_type == PTH_EVENT_COND) { if (ev->ev_args.COND.cond->cn_state & PTH_COND_SIGNALED) { if (ev->ev_args.COND.cond->cn_state & PTH_COND_BROADCAST) this_occurred = TRUE; else { if (!(ev->ev_args.COND.cond->cn_state & PTH_COND_HANDLED)) { ev->ev_args.COND.cond->cn_state |= PTH_COND_HANDLED; this_occurred = TRUE; } } } } /* Thread Termination */ else if (ev->ev_type == PTH_EVENT_TID) { if ( ( ev->ev_args.TID.tid == NULL && pth_pqueue_elements(&pth_DQ) > 0) || ( ev->ev_args.TID.tid != NULL && ev->ev_args.TID.tid->state == ev->ev_goal)) this_occurred = TRUE; } /* Custom Event Function */ else if (ev->ev_type == PTH_EVENT_FUNC) { if (ev->ev_args.FUNC.func(ev->ev_args.FUNC.arg)) this_occurred = TRUE; else { pth_time_t tv; pth_time_set(&tv, now); pth_time_add(&tv, &(ev->ev_args.FUNC.tv)); if ((nexttimer_thread == NULL && nexttimer_ev == NULL) || pth_time_cmp(&tv, &nexttimer_value) < 0) { nexttimer_thread = t; nexttimer_ev = ev; pth_time_set(&nexttimer_value, &tv); } } } /* tag event if it has occurred */ if (this_occurred) { pth_debug2("pth_sched_eventmanager: [non-I/O] event occurred for thread \"%s\"", t->name); ev->ev_status = PTH_STATUS_OCCURRED; any_occurred = TRUE; } } } while ((ev = ev->ev_next) != evh); } if (any_occurred) dopoll = TRUE; /* now decide how to poll for fd I/O and timers */ if (dopoll) { /* do a polling with immediate timeout, i.e. check the fd sets only without blocking */ pth_time_set(&delay, PTH_TIME_ZERO); pdelay = &delay; } else if (nexttimer_ev != NULL) { /* do a polling with a timeout set to the next timer, i.e. wait for the fd sets or the next timer */ pth_time_set(&delay, &nexttimer_value); pth_time_sub(&delay, now); pdelay = &delay; } else { /* do a polling without a timeout, i.e. wait for the fd sets only with blocking */ pdelay = NULL; } /* clear pipe and let select() wait for the read-part of the pipe */ while (pth_sc(read)(pth_sigpipe[0], minibuf, sizeof(minibuf)) > 0) ; FD_SET(pth_sigpipe[0], &rfds); if (fdmax < pth_sigpipe[0]) fdmax = pth_sigpipe[0]; /* replace signal actions for signals we've to catch for events */ for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(&pth_sigcatch, sig)) { sa.sa_handler = pth_sched_eventmanager_sighandler; sigfillset(&sa.sa_mask); sa.sa_flags = 0; sigaction(sig, &sa, &osa[sig]); } } /* allow some signals to be delivered: Either to our catching handler or directly to the configured handler for signals not catched by events */ pth_sc(sigprocmask)(SIG_SETMASK, &pth_sigblock, &oss); /* now do the polling for filedescriptor I/O and timers WHEN THE SCHEDULER SLEEPS AT ALL, THEN HERE!! */ rc = -1; if (!(dopoll && fdmax == -1)) while ((rc = pth_sc(select)(fdmax+1, &rfds, &wfds, &efds, pdelay)) < 0 && errno == EINTR) ; /* restore signal mask and actions and handle signals */ pth_sc(sigprocmask)(SIG_SETMASK, &oss, NULL); for (sig = 1; sig < PTH_NSIG; sig++) if (sigismember(&pth_sigcatch, sig)) sigaction(sig, &osa[sig], NULL); /* if the timer elapsed, handle it */ if (!dopoll && rc == 0 && nexttimer_ev != NULL) { if (nexttimer_ev->ev_type == PTH_EVENT_FUNC) { /* it was an implicit timer event for a function event, so repeat the event handling for rechecking the function */ loop_repeat = TRUE; } else { /* it was an explicit timer event, standing for its own */ pth_debug2("pth_sched_eventmanager: [timeout] event occurred for thread \"%s\"", nexttimer_thread->name); nexttimer_ev->ev_status = PTH_STATUS_OCCURRED; } } /* if the internal signal pipe was used, adjust the select() results */ if (!dopoll && rc > 0 && FD_ISSET(pth_sigpipe[0], &rfds)) { FD_CLR(pth_sigpipe[0], &rfds); rc--; } /* if an error occurred, avoid confusion in the cleanup loop */ if (rc <= 0) { FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); } /* now comes the final cleanup loop where we've to do two jobs: first we've to do the late handling of the fd I/O events and additionally if a thread has one occurred event, we move it from the waiting queue to the ready queue */ /* for all threads in the waiting queue... */ t = pth_pqueue_head(&pth_WQ); while (t != NULL) { /* do the late handling of the fd I/O and signal events in the waiting event ring */ any_occurred = FALSE; if (t->events != NULL) { ev = evh = t->events; do { /* * Late handling for still not occured events */ if (ev->ev_status == PTH_STATUS_PENDING) { /* Filedescriptor I/O */ if (ev->ev_type == PTH_EVENT_FD) { if ( ( ev->ev_goal & PTH_UNTIL_FD_READABLE && FD_ISSET(ev->ev_args.FD.fd, &rfds)) || ( ev->ev_goal & PTH_UNTIL_FD_WRITEABLE && FD_ISSET(ev->ev_args.FD.fd, &wfds)) || ( ev->ev_goal & PTH_UNTIL_FD_EXCEPTION && FD_ISSET(ev->ev_args.FD.fd, &efds)) ) { pth_debug2("pth_sched_eventmanager: " "[I/O] event occurred for thread \"%s\"", t->name); ev->ev_status = PTH_STATUS_OCCURRED; } else if (rc < 0) { /* re-check particular filedescriptor */ int rc2; if (ev->ev_goal & PTH_UNTIL_FD_READABLE) FD_SET(ev->ev_args.FD.fd, &rfds); if (ev->ev_goal & PTH_UNTIL_FD_WRITEABLE) FD_SET(ev->ev_args.FD.fd, &wfds); if (ev->ev_goal & PTH_UNTIL_FD_EXCEPTION) FD_SET(ev->ev_args.FD.fd, &efds); pth_time_set(&delay, PTH_TIME_ZERO); while ((rc2 = pth_sc(select)(ev->ev_args.FD.fd+1, &rfds, &wfds, &efds, &delay)) < 0 && errno == EINTR) ; if (rc2 > 0) { /* cleanup afterwards for next iteration */ FD_CLR(ev->ev_args.FD.fd, &rfds); FD_CLR(ev->ev_args.FD.fd, &wfds); FD_CLR(ev->ev_args.FD.fd, &efds); } else if (rc2 < 0) { /* cleanup afterwards for next iteration */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); ev->ev_status = PTH_STATUS_FAILED; pth_debug2("pth_sched_eventmanager: " "[I/O] event failed for thread \"%s\"", t->name); } } } /* Filedescriptor Set I/O */ else if (ev->ev_type == PTH_EVENT_SELECT) { if (pth_util_fds_test(ev->ev_args.SELECT.nfd, ev->ev_args.SELECT.rfds, &rfds, ev->ev_args.SELECT.wfds, &wfds, ev->ev_args.SELECT.efds, &efds)) { n = pth_util_fds_select(ev->ev_args.SELECT.nfd, ev->ev_args.SELECT.rfds, &rfds, ev->ev_args.SELECT.wfds, &wfds, ev->ev_args.SELECT.efds, &efds); if (ev->ev_args.SELECT.n != NULL) *(ev->ev_args.SELECT.n) = n; ev->ev_status = PTH_STATUS_OCCURRED; pth_debug2("pth_sched_eventmanager: " "[I/O] event occurred for thread \"%s\"", t->name); } else if (rc < 0) { /* re-check particular filedescriptor set */ int rc2; fd_set *prfds = NULL; fd_set *pwfds = NULL; fd_set *pefds = NULL; fd_set trfds; fd_set twfds; fd_set tefds; if (ev->ev_args.SELECT.rfds) { memcpy(&trfds, ev->ev_args.SELECT.rfds, sizeof(rfds)); prfds = &trfds; } if (ev->ev_args.SELECT.wfds) { memcpy(&twfds, ev->ev_args.SELECT.wfds, sizeof(wfds)); pwfds = &twfds; } if (ev->ev_args.SELECT.efds) { memcpy(&tefds, ev->ev_args.SELECT.efds, sizeof(efds)); pefds = &tefds; } pth_time_set(&delay, PTH_TIME_ZERO); while ((rc2 = pth_sc(select)(ev->ev_args.SELECT.nfd+1, prfds, pwfds, pefds, &delay)) < 0 && errno == EINTR) ; if (rc2 < 0) { ev->ev_status = PTH_STATUS_FAILED; pth_debug2("pth_sched_eventmanager: " "[I/O] event failed for thread \"%s\"", t->name); } } } /* Signal Set */ else if (ev->ev_type == PTH_EVENT_SIGS) { for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(ev->ev_args.SIGS.sigs, sig)) { if (sigismember(&pth_sigraised, sig)) { if (ev->ev_args.SIGS.sig != NULL) *(ev->ev_args.SIGS.sig) = sig; pth_debug2("pth_sched_eventmanager: " "[signal] event occurred for thread \"%s\"", t->name); sigdelset(&pth_sigraised, sig); ev->ev_status = PTH_STATUS_OCCURRED; } } } } } /* * post-processing for already occured events */ else { /* Condition Variable Signal */ if (ev->ev_type == PTH_EVENT_COND) { /* clean signal */ if (ev->ev_args.COND.cond->cn_state & PTH_COND_SIGNALED) { ev->ev_args.COND.cond->cn_state &= ~(PTH_COND_SIGNALED); ev->ev_args.COND.cond->cn_state &= ~(PTH_COND_BROADCAST); ev->ev_args.COND.cond->cn_state &= ~(PTH_COND_HANDLED); } } } /* local to global mapping */ if (ev->ev_status != PTH_STATUS_PENDING) any_occurred = TRUE; } while ((ev = ev->ev_next) != evh); } /* cancellation support */ if (t->cancelreq == TRUE) { pth_debug2("pth_sched_eventmanager: cancellation request pending for thread \"%s\"", t->name); any_occurred = TRUE; } /* walk to next thread in waiting queue */ tlast = t; t = pth_pqueue_walk(&pth_WQ, t, PTH_WALK_NEXT); /* * move last thread to ready queue if any events occurred for it. * we insert it with a slightly increased queue priority to it a * better chance to immediately get scheduled, else the last running * thread might immediately get again the CPU which is usually not * what we want, because we oven use pth_yield() calls to give others * a chance. */ if (any_occurred) { pth_pqueue_delete(&pth_WQ, tlast); tlast->state = PTH_STATE_READY; pth_pqueue_insert(&pth_RQ, tlast->prio+1, tlast); pth_debug2("pth_sched_eventmanager: thread \"%s\" moved from waiting " "to ready queue", tlast->name); } } /* perhaps we have to internally loop... */ if (loop_repeat) { pth_time_set(now, PTH_TIME_NOW); goto loop_entry; } pth_debug1("pth_sched_eventmanager: leaving"); return; }
static void * softsig_thread(void *arg) { sigset_t ss, os; int i; sigemptyset(&ss); /* get the list of signals _not_ blocked by AFS_SIGSET_CLEAR() */ pthread_sigmask(SIG_BLOCK, &ss, &os); pthread_sigmask(SIG_SETMASK, &os, NULL); sigaddset(&ss, SIGUSR1); #if defined(AFS_DARWIN_ENV) || (defined(AFS_NBSD_ENV) && !defined(AFS_NBSD50_ENV)) pthread_sigmask (SIG_BLOCK, &ss, NULL); sigdelset (&os, SIGUSR1); #elif !defined(AFS_HPUX_ENV) /* On HPUX, don't wait for 'critical' signals, as things such as * SEGV won't cause a core, then. Some non-HPUX platforms may need * this, though, since apparently if we wait on some signals but not * e.g. SEGV, the softsig thread will still wait around when the * other threads were killed by the SEGV. */ for (i = 0; i < NSIG; i++) { if (!sigismember(&os, i) && i != SIGSTOP && i != SIGKILL) { sigaddset(&ss, i); softsig_sigs[i].fatal = 1; } } #endif /* defined(AFS_DARWIN_ENV) || defined(AFS_NBSD_ENV) */ while (1) { void (*h) (int); #if !defined(AFS_DARWIN_ENV) && (!defined(AFS_NBSD_ENV) || defined(AFS_NBSD50_ENV)) int sigw; #endif h = NULL; for (i = 0; i < NSIG; i++) { if (softsig_sigs[i].handler && !softsig_sigs[i].inited) { sigaddset(&ss, i); #if defined(AFS_DARWIN_ENV) || (defined(AFS_NBSD_ENV) && !defined(AFS_NBSD50_ENV)) pthread_sigmask (SIG_BLOCK, &ss, NULL); sigdelset (&os, i); #endif /* defined(AFS_DARWIN_ENV) || defined(AFS_NBSD_ENV) */ softsig_sigs[i].inited = 1; } if (softsig_sigs[i].pending) { softsig_sigs[i].pending = 0; h = softsig_sigs[i].handler; break; } } if (i == NSIG) { #if defined(AFS_DARWIN_ENV) || (defined(AFS_NBSD_ENV) && !defined(AFS_NBSD50_ENV)) sigsuspend (&os); #else /* !defined(AFS_DARWIN_ENV) && !defined(AFS_NBSD_ENV) */ sigwait(&ss, &sigw); if (sigw != SIGUSR1) { if (softsig_sigs[sigw].fatal) exit(0); softsig_sigs[sigw].pending = 1; } #endif /* defined(AFS_DARWIN_ENV) || defined(AFS_NBSD_ENV) */ } else if (h) h(i); } return NULL; }
unsigned int mysleep(unsigned int nsecs) { #ifdef DEBUG printf("DEBUG - mysleep(%u)\n", nsecs); #endif struct sigaction newact, oldact; sigset_t newmask, oldmask, suspmask, blockedmask; int issuspend = 0;/* SIGALRM是否被阻塞 */ int isblocked = 0;/* 是否存在未决的SIGALRM */ unsigned int unslept, slept; unsigned int oldalarm; oldalarm = alarm(0); /* 保存以前的SIGALRM配置,并设置成我们需要的配置 */ newact.sa_handler = sig_alrm; sigemptyset(&newact.sa_mask); newact.sa_flags = 0; sigaction(SIGALRM, &newact, &oldact); /* 处理以前的SIGALRM */ /* 判断SIGALRM是否被阻塞 */ sigprocmask(SIG_BLOCK, NULL, &oldmask); if (sigismember(&oldmask, SIGALRM)) { /* SIGALRM被阻塞 */ issuspend = 1; } /* 判断是否存在未决的SIGALRM */ if (sigpending(&blockedmask) < 0) { err_sys("sigpending error"); } if (sigismember(&blockedmask, SIGALRM)) { /* 存在未决的SIGALRM */ suspmask = oldmask; isblocked = 1; sigdelset(&suspmask, SIGALRM); sigsuspend(&suspmask); sigprocmask(SIG_SETMASK, &oldmask, NULL); } sigemptyset(&newmask); sigaddset(&newmask, SIGALRM); sigprocmask(SIG_BLOCK, &newmask, &oldmask); #ifdef DEBUG printf("DEBUG - oldalarm = %u\n", oldalarm); #endif if ((oldalarm != 0) && (oldalarm < nsecs) && (issuspend == 0)) { /* 以前剩余的闹钟值比睡眠时间少且没有被阻塞 */ alarm(oldalarm); } else { /* 以前剩余的闹钟值比睡眠时间多或者被阻塞 */ alarm(nsecs); } suspmask = oldmask; sigdelset(&suspmask, SIGALRM); sigsuspend(&suspmask); unslept = alarm(0); sigaction(SIGALRM, &oldact, NULL); sigprocmask(SIG_SETMASK, &oldmask, NULL); /* 计算实际睡眠时间 */ if ((oldalarm != 0) && (oldalarm < nsecs) && (issuspend == 0)) { /* 以前的闹钟值比睡眠时间少 */ slept = oldalarm - unslept; } else { /* 以前的闹钟值比睡眠时间多 */ slept = nsecs - unslept; } if (isblocked == 1) { kill(getpid(), SIGALRM); } if (slept < oldalarm) { /* 以前的闹钟值比实际睡眠时间多 */ alarm(oldalarm - slept); return nsecs - slept; } else { if (oldalarm != 0) { kill(getpid(), SIGALRM); } return nsecs - slept; } return 0; /* 出错 */ }
/* The main test function. */ int main(int argc, char * argv[]) { int ret, status; pid_t child, ctl; sigset_t mask, pending; /* Initialize output */ output_init(); /* block SIGUSR1 and SIGUSR2 */ ret = sigemptyset(&mask); if (ret != 0) { UNRESOLVED(errno, "Failed to initialize signal set"); } ret = sigaddset(&mask, SIGUSR1); if (ret != 0) { UNRESOLVED(errno, "Failed to add SIGUSR1 to signal set"); } ret = sigaddset(&mask, SIGUSR2); if (ret != 0) { UNRESOLVED(errno, "Failed to add SIGUSR2 to signal set"); } ret = sigprocmask(SIG_BLOCK, &mask, NULL); if (ret != 0) { UNRESOLVED(errno, "Sigprocmask failed"); } /* Make the signals pending */ ret = kill(getpid(), SIGUSR1); if (ret != 0) { UNRESOLVED(errno, "failed to kill with SIGUSR1"); } ret = kill(getpid(), SIGUSR2); if (ret != 0) { UNRESOLVED(errno, "failed to kill with SIGUSR2"); } do { ret = sigpending(&pending); if (ret != 0) { UNRESOLVED(errno, "failed to examine pending signal set"); } ret = sigismember(&pending, SIGUSR1); if (ret < 0) { UNRESOLVED(errno, "Unable to check signal USR1 presence"); } if (ret == 1) { ret = sigismember(&pending, SIGUSR2); if (ret < 0) { UNRESOLVED(errno, "Unable to check signal USR2 presence"); } } } while (ret != 1); #if VERBOSE > 0 output("SIGUSR1 and SIGUSR2 are pending, we can fork\n"); #endif /* Create the child */ child = fork(); if (child == -1) { UNRESOLVED(errno, "Failed to fork"); } /* child */ if (child == 0) { /* Examine the current blocked signal set. USR1 & USR2 shall be present */ ret = sigprocmask(0, NULL, &mask); if (ret != 0) { UNRESOLVED(errno, "Sigprocmask failed in child"); } ret = sigismember(&mask, SIGUSR1); if (ret < 0) { UNRESOLVED(errno, "Unable to check signal USR1 presence"); } if (ret == 0) { FAILED("The new process does not mask SIGUSR1 as its parent"); } ret = sigismember(&mask, SIGUSR2); if (ret < 0) { UNRESOLVED(errno, "Unable to check signal USR2 presence"); } if (ret == 0) { FAILED("The new process does not mask SIGUSR2 as its parent"); } #if VERBOSE > 0 output("SIGUSR1 and SIGUSR2 are blocked in child\n"); #endif /* Examine pending signals */ ret = sigpending(&pending); if (ret != 0) { UNRESOLVED(errno, "failed to examine pending signal set in child"); } ret = sigismember(&pending, SIGUSR1); if (ret < 0) { UNRESOLVED(errno, "Unable to check signal USR1 presence"); } if (ret != 0) { FAILED("The new process was created with SIGUSR1 pending"); } ret = sigismember(&pending, SIGUSR2); if (ret < 0) { UNRESOLVED(errno, "Unable to check signal USR2 presence"); } if (ret != 0) { FAILED("The new process was created with SIGUSR2 pending"); } #if VERBOSE > 0 output("SIGUSR1 and SIGUSR2 are not pending in child\n"); #endif /* We're done */ exit(PTS_PASS); } /* Parent joins the child */ ctl = waitpid(child, &status, 0); if (ctl != child) { UNRESOLVED(errno, "Waitpid returned the wrong PID"); } if (!WIFEXITED(status) || (WEXITSTATUS(status) != PTS_PASS)) { FAILED("Child exited abnormally"); } /* Test passed */ #if VERBOSE > 0 output("Test passed\n"); #endif PASSED; }
void *pthread_entry1( void *arg) { sigset_t mask; siginfo_t info; struct timespec timeout; int sig, sig2, err; CYG_TEST_INFO( "Thread 1 running" ); // Should have inherited parent's signal mask pthread_sigmask( 0, NULL, &mask ); CYG_TEST_CHECK( sigismember( &mask, SIGALRM), "SIGALRM mask inherited"); CYG_TEST_CHECK( sigismember( &mask, SIGUSR1), "SIGUSR1 mask inherited"); CYG_TEST_CHECK( sigismember( &mask, SIGUSR2), "SIGUSR2 mask inherited"); CYG_TEST_CHECK( sigismember( &mask, SIGSEGV), "SIGSEGV mask inherited"); // Make a full set sigfillset( &mask ); // remove USR2 and ALRM signals sigdelset( &mask, SIGUSR2 ); sigdelset( &mask, SIGALRM ); // Set signal mask pthread_sigmask( SIG_SETMASK, &mask, NULL ); // Get main thread going again sem_post( &sem ); // set up timeout timeout.tv_sec = 10; timeout.tv_nsec = 0; CYG_TEST_INFO( "Thread1: calling sigtimedwait()"); // Wait for a signal to be delivered sig = sigtimedwait( &mask, &info, &timeout ); sig2 = info.si_signo; CYG_TEST_CHECK( sig == sig2, "sigtimedwait return value not equal"); CYG_TEST_CHECK( sig == SIGUSR1, "Signal not delivered"); while( sigusr2_called != 2 ) { CYG_TEST_INFO( "Thread1: calling pause()"); pause(); } errno = 0; // strictly correct to reset errno first // now wait for SIGALRM to be delivered CYG_TEST_INFO( "Thread1: calling pause()"); err = pause(); CYG_TEST_CHECK( -1==err, "pause returned -1"); CYG_TEST_CHECK( EINTR==errno, "errno set to EINTR"); // generate another SIGALRM and wait for it to be delivered too // we need to mask it first though // Make a full set sigfillset( &mask ); // Set signal mask pthread_sigmask( SIG_SETMASK, &mask, NULL ); alarm(1); CYG_TEST_INFO( "Thread1: calling sigwait()"); err = sigwait( &mask, &sig); CYG_TEST_CHECK( 0==err, "sigwait returned -1"); CYG_TEST_CHECK( sig==SIGALRM, "sigwait caught alarm"); CYG_TEST_INFO( "Thread1: calling pthread_exit()"); pthread_exit( (void *)((int)arg+sig2) ); }
int main(int argc, char **argv) { video_playback_setup *settings; sigset_t allsignals; struct sigaction action; struct timespec req; int i; fflush(stdout); vj_mem_init(); vevo_strict_init(); info = veejay_malloc(); if (!info) { vj_mem_threaded_stop(); return 1; } settings = (video_playback_setup *) info->settings; if(!check_command_line_options(argc, argv)) { veejay_free(info); return 0; } if(info->dump) { veejay_set_colors(0); vj_event_init(NULL); vj_effect_initialize(720,576,0); vj_osc_allocate(VJ_PORT+2); vj_event_dump(); vj_effect_dump(); fprintf(stdout, "Environment variables:\n\tSDL_VIDEO_HWACCEL\t\tSet to 1 to use SDL video hardware accel (default=on)\n\tVEEJAY_PERFORMANCE\t\tSet to \"quality\" or \"fastest\" (default is fastest)\n\tVEEJAY_AUTO_SCALE_PIXELS\tSet to 1 to convert between CCIR 601 and JPEG automatically (default=dont care)\n\tVEEJAY_INTERPOLATE_CHROMA\tSet to 1 if you wish to interpolate every chroma sample when scaling (default=0)\n\tVEEJAY_CAPTURE_DRIVER\t\tSet to \"unicap\" or \"v4lutils\" (default=v4lutils)\n\tVEEJAY_SDL_KEY_REPEAT_INTERVAL\tinterval of key pressed to repeat while pressed down.\n\tVEEJAY_PLAYBACK_CACHE\t\tSample cache size in MB - by default, veejay takes 30 percent of total RAM\n\tVEEJAY_SDL_KEY_REPEAT_DELAY\tDelay key repeat in ms\n\tVEEJAY_FULLSCREEN\t\tStart in fullscreen (1) or windowed (0) mode\n\tVEEJAY_SCREEN_GEOMETRY\t\tSpecifiy a geometry for veejay to position the video window.\n\tVEEJAY_SCREEN_SIZE\t\tSize of video window, defaults to full screen size.\n\tVEEJAY_RUN_MODE\t\t\tRun in \"classic\" (352x288 Dummy) or default (720x576). \n"); fprintf(stdout, "\n\n\tExample for bash:\n\t\t\t$ export VEEJAY_AUTO_SCALE_PIXEL=1\n"); veejay_free(info); return 0; } if( vj_el_get_mem_size() == 0 ) prepare_cache_line( max_mem_, n_slots_ ); veejay_check_homedir( info ); sigsegfault_handler(); sigemptyset(&(settings->signal_set)); sigaddset(&(settings->signal_set), SIGINT); sigaddset(&(settings->signal_set), SIGPIPE); sigaddset(&(settings->signal_set), SIGILL); // sigaddset(&(settings->signal_set), SIGSEGV); sigaddset(&(settings->signal_set), SIGFPE ); sigaddset(&(settings->signal_set), SIGTERM ); sigaddset(&(settings->signal_set), SIGABRT); sigaddset(&(settings->signal_set), SIGPWR ); sigaddset(&(settings->signal_set), SIGQUIT ); sigfillset( &allsignals ); action.sa_handler = donothing; action.sa_mask = allsignals; action.sa_flags = SA_SIGINFO | SA_ONESHOT ; //SA_RESTART | SA_RESETHAND; signal( SIGPIPE, SIG_IGN ); for( i = 1; i < NSIG; i ++ ) if( sigismember( &(settings->signal_set), i )) sigaction( i, &action, 0 ); char *mem_func = get_memcpy_descr(); if(mem_func) { veejay_msg(VEEJAY_MSG_INFO, "Using SIMD %s", mem_func); free(mem_func); } info->use_keyb = use_keyb; info->use_mouse = use_mouse; info->show_cursor = show_cursor; if(veejay_init( info, default_geometry_x, default_geometry_y, NULL, live, ta )< 0) { veejay_msg(VEEJAY_MSG_ERROR, "Cannot start veejay"); return 0; } if(auto_loop) veejay_auto_loop(info); print_license(); veejay_init_msg_ring(); // rest of logging to screen if(!veejay_main(info)) { veejay_msg(VEEJAY_MSG_ERROR, "Cannot start main playback cycle"); veejay_free(info); return 1; } veejay_msg(VEEJAY_MSG_DEBUG, "Started playback"); int current_state = LAVPLAY_STATE_PLAYING; req.tv_sec = 0; req.tv_nsec = 4000 * 1000; while( 1 ) { //@ until your PC stops working clock_nanosleep( CLOCK_REALTIME, 0, &req, NULL ); current_state = veejay_get_state(info); if( current_state == LAVPLAY_STATE_STOP ) break; } veejay_busy(info); veejay_free(info); veejay_destroy_msg_ring(); veejay_msg(VEEJAY_MSG_INFO, "Thank you for using Veejay"); return 0; }
static int dpram_thread(void *data) { int ret = 0; //unsigned long flags; struct file *filp; dpram_task = current; daemonize("dpram_thread"); //reparent_to_init(); // for 2.6 kernel porting : this seems not to be used in driver // current->tty = NULL; // for 2.6 kernel porting strcpy(current->comm, "multipdp"); /* set signals to accept */ //spin_lock_irqsave(¤t->sigmask_lock, flags); // for 2.6 kernel proting siginitsetinv(¤t->blocked, sigmask(SIGUSR1)); //recalc_sigpending(current); recalc_sigpending(); //spin_unlock_irqrestore(¤t->sigmask_lock, flags); // for 2.6 kernel proting filp = dpram_open(); if (filp == NULL) { goto out; } dpram_filp = filp; /* send start signal */ complete(&dpram_complete); while (1) { ret = dpram_poll(filp); if (ret == -ERESTARTSYS) { if (sigismember(¤t->pending.signal, SIGUSR1)) { printk(KERN_ERR "MULTIPDP (%s) DPRAM device communication interrupted\n",__func__); sigdelset(¤t->pending.signal, SIGUSR1); recalc_sigpending(); ret = 0; break; } } else if (ret < 0) { EPRINTK("dpram_poll() failed\n"); break; } else { char ch; dpram_read(dpram_filp, &ch, sizeof(ch)); if (ch == 0x7f) { pdp_demux(); } } try_to_freeze(); } dpram_close(filp); dpram_filp = NULL; out: dpram_task = NULL; /* send finish signal and exit */ complete_and_exit(&dpram_complete, ret); }
/* * This is not really a trans2 request, we assume that you only have * one packet to send. */ int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, int ldata, unsigned char *data, int lparam, unsigned char *param, int *lrdata, unsigned char **rdata, int *lrparam, unsigned char **rparam) { sigset_t old_set; unsigned long flags, sigpipe; mm_segment_t fs; int result; pr_debug("smb_trans2_request: com=%d, ld=%d, lp=%d\n", trans2_command, ldata, lparam); /* * These are initialized in smb_request_ok, but not here?? */ server->rcls = 0; server->err = 0; result = -EIO; if (server->state != CONN_VALID) goto out; if ((result = smb_dont_catch_keepalive(server)) != 0) goto bad_conn; spin_lock_irqsave(¤t->sigmask_lock, flags); sigpipe = sigismember(¤t->signal, SIGPIPE); old_set = current->blocked; siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); fs = get_fs(); set_fs(get_ds()); result = smb_send_trans2(server, trans2_command, ldata, data, lparam, param); if (result >= 0) { result = smb_receive_trans2(server, lrdata, rdata, lrparam, rparam); } /* read/write errors are handled by errno */ spin_lock_irqsave(¤t->sigmask_lock, flags); if (result == -EPIPE && !sigpipe) sigdelset(¤t->signal, SIGPIPE); current->blocked = old_set; recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); set_fs(fs); if (result >= 0) { int result2 = smb_catch_keepalive(server); if (result2 < 0) { result = result2; } } if (result < 0) goto bad_conn; /* * Check for fatal server errors ... */ if (server->rcls) { int error = smb_errno(server); if (error == EBADSLT) { printk("smb_request: tree ID invalid\n"); result = error; goto bad_conn; } } out: return result; bad_conn: #ifdef SMBFS_PARANOIA printk("smb_trans2_request: result=%d, setting invalid\n", result); #endif server->state = CONN_INVALID; smb_invalidate_inodes(server); goto out; }
/* * stress_sigpending * stress sigpending system call */ int stress_sigpending( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { struct sigaction new_action; sigset_t sigset; const pid_t mypid = getpid(); (void)instance; memset(&new_action, 0, sizeof new_action); new_action.sa_handler = stress_usr1_handler; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; if (sigaction(SIGUSR1, &new_action, NULL) < 0) { pr_failed_err(name, "sigaction"); return EXIT_FAILURE; } do { sigemptyset(&sigset); sigaddset(&sigset, SIGUSR1); if (sigprocmask(SIG_SETMASK, &sigset, NULL) < 0) { pr_failed_err(name, "sigprocmask"); return EXIT_FAILURE; } (void)kill(mypid, SIGUSR1); if (sigpending(&sigset) < 0) { pr_failed_err(name, "sigpending"); continue; } /* We should get a SIGUSR1 here */ if (!sigismember(&sigset, SIGUSR1)) { pr_failed_err(name, "sigismember"); continue; } /* Unmask signal, signal is handled */ sigemptyset(&sigset); sigprocmask(SIG_SETMASK, &sigset, NULL); /* And it is no longer pending */ if (sigpending(&sigset) < 0) { pr_failed_err(name, "sigpending"); continue; } if (sigismember(&sigset, SIGUSR1)) { pr_failed_err(name, "sigismember"); continue; } /* Success! */ (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); return EXIT_SUCCESS; }
/* * Called with the server locked */ int smb_request(struct smb_sb_info *server) { unsigned long flags, sigpipe; mm_segment_t fs; sigset_t old_set; int len, result; unsigned char *buffer; result = -EBADF; buffer = server->packet; if (!buffer) goto bad_no_packet; result = -EIO; if (server->state != CONN_VALID) goto bad_no_conn; if ((result = smb_dont_catch_keepalive(server)) != 0) goto bad_conn; len = smb_len(buffer) + 4; pr_debug("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]); spin_lock_irqsave(¤t->sigmask_lock, flags); sigpipe = sigismember(¤t->signal, SIGPIPE); old_set = current->blocked; siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); fs = get_fs(); set_fs(get_ds()); result = smb_send_raw(server_sock(server), (void *) buffer, len); if (result > 0) { result = smb_receive(server); } /* read/write errors are handled by errno */ spin_lock_irqsave(¤t->sigmask_lock, flags); if (result == -EPIPE && !sigpipe) sigdelset(¤t->signal, SIGPIPE); current->blocked = old_set; recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); set_fs(fs); if (result >= 0) { int result2 = smb_catch_keepalive(server); if (result2 < 0) { printk("smb_request: catch keepalive failed\n"); result = result2; } } if (result < 0) goto bad_conn; /* * Check for fatal server errors ... */ if (server->rcls) { int error = smb_errno(server); if (error == EBADSLT) { printk("smb_request: tree ID invalid\n"); result = error; goto bad_conn; } } out: pr_debug("smb_request: result = %d\n", result); return result; bad_conn: #ifdef SMBFS_PARANOIA printk("smb_request: result %d, setting invalid\n", result); #endif server->state = CONN_INVALID; smb_invalidate_inodes(server); goto out; bad_no_packet: printk("smb_request: no packet!\n"); goto out; bad_no_conn: printk("smb_request: connection %d not valid!\n", server->state); goto out; }
/*===========================================================================* * do_exec * *===========================================================================*/ PUBLIC int do_exec() { /* Perform the execve(name, argv, envp) call. The user library builds a * complete stack image, including pointers, args, environ, etc. The stack * is copied to a buffer inside MM, and then to the new core image. */ register struct mproc *rmp; struct mproc *sh_mp; int m, r, fd, ft, sn; static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ static char name_buf[PATH_MAX]; /* the name of the file to exec */ char *new_sp, *basename; vir_bytes src, dst, text_bytes, data_bytes, bss_bytes, stk_bytes, vsp; phys_bytes tot_bytes; /* total space for program, including gap */ long sym_bytes; vir_clicks sc; struct stat s_buf; vir_bytes pc; /* Do some validity checks. */ rmp = mp; stk_bytes = (vir_bytes) stack_bytes; if (stk_bytes > ARG_MAX) return(ENOMEM); /* stack too big */ if (exec_len <= 0 || exec_len > PATH_MAX) return(EINVAL); /* Get the exec file name and see if the file is executable. */ src = (vir_bytes) exec_name; dst = (vir_bytes) name_buf; r = sys_copy(who, D, (phys_bytes) src, MM_PROC_NR, D, (phys_bytes) dst, (phys_bytes) exec_len); if (r != OK) return(r); /* file name not in user data segment */ tell_fs(CHDIR, who, FALSE, 0); /* switch to the user's FS environ. */ fd = allowed(name_buf, &s_buf, X_BIT); /* is file executable? */ if (fd < 0) return(fd); /* file was not executable */ /* Read the file header and extract the segment sizes. */ sc = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; m = read_header(fd, &ft, &text_bytes, &data_bytes, &bss_bytes, &tot_bytes, &sym_bytes, sc, &pc); if (m < 0) { close(fd); /* something wrong with header */ return(ENOEXEC); } /* Fetch the stack from the user before destroying the old core image. */ src = (vir_bytes) stack_ptr; dst = (vir_bytes) mbuf; r = sys_copy(who, D, (phys_bytes) src, MM_PROC_NR, D, (phys_bytes) dst, (phys_bytes)stk_bytes); if (r != OK) { close(fd); /* can't fetch stack (e.g. bad virtual addr) */ return(EACCES); } /* Can the process' text be shared with that of one already running? */ sh_mp = find_share(rmp, s_buf.st_ino, s_buf.st_dev, s_buf.st_ctime); /* Allocate new memory and release old memory. Fix map and tell kernel. */ r = new_mem(sh_mp, text_bytes, data_bytes, bss_bytes, stk_bytes, tot_bytes); if (r != OK) { close(fd); /* insufficient core or program too big */ return(r); } /* Save file identification to allow it to be shared. */ rmp->mp_ino = s_buf.st_ino; rmp->mp_dev = s_buf.st_dev; rmp->mp_ctime = s_buf.st_ctime; /* Patch up stack and copy it from MM to new core image. */ vsp = (vir_bytes) rmp->mp_seg[S].mem_vir << CLICK_SHIFT; vsp += (vir_bytes) rmp->mp_seg[S].mem_len << CLICK_SHIFT; vsp -= stk_bytes; patch_ptr(mbuf, vsp); src = (vir_bytes) mbuf; r = sys_copy(MM_PROC_NR, D, (phys_bytes) src, who, D, (phys_bytes) vsp, (phys_bytes)stk_bytes); if (r != OK) panic("do_exec stack copy err", NO_NUM); /* Read in text and data segments. */ if (sh_mp != NULL) { lseek(fd, (off_t) text_bytes, SEEK_CUR); /* shared: skip text */ } else { load_seg(fd, T, text_bytes); } load_seg(fd, D, data_bytes); #if (SHADOWING == 1) if (lseek(fd, (off_t)sym_bytes, SEEK_CUR) == (off_t) -1) ; /* error */ if (relocate(fd, (unsigned char *)mbuf) < 0) ; /* error */ pc += (vir_bytes) rp->mp_seg[T].mem_vir << CLICK_SHIFT; #endif close(fd); /* don't need exec file any more */ /* Take care of setuid/setgid bits. */ if ((rmp->mp_flags & TRACED) == 0) { /* suppress if tracing */ if (s_buf.st_mode & I_SET_UID_BIT) { rmp->mp_effuid = s_buf.st_uid; tell_fs(SETUID,who, (int)rmp->mp_realuid, (int)rmp->mp_effuid); } if (s_buf.st_mode & I_SET_GID_BIT) { rmp->mp_effgid = s_buf.st_gid; tell_fs(SETGID,who, (int)rmp->mp_realgid, (int)rmp->mp_effgid); } } /* Save offset to initial argc (for ps) */ rmp->mp_procargs = vsp; /* Fix 'mproc' fields, tell kernel that exec is done, reset caught sigs. */ for (sn = 1; sn <= _NSIG; sn++) { if (sigismember(&rmp->mp_catch, sn)) { sigdelset(&rmp->mp_catch, sn); rmp->mp_sigact[sn].sa_handler = SIG_DFL; sigemptyset(&rmp->mp_sigact[sn].sa_mask); } } rmp->mp_flags &= ~SEPARATE; /* turn off SEPARATE bit */ rmp->mp_flags |= ft; /* turn it on for separate I & D files */ new_sp = (char *) vsp; tell_fs(EXEC, who, 0, 0); /* allow FS to handle FD_CLOEXEC files */ /* System will save command line for debugging, ps(1) output, etc. */ basename = strrchr(name_buf, '/'); if (basename == NULL) basename = name_buf; else basename++; sys_exec(who, new_sp, rmp->mp_flags & TRACED, basename, pc); return(OK); }
/* Handlers intialization */ void signal_handler_init(int remember) { sigset_t sset; int sig; struct sigaction act, oact; int n; #ifdef HAVE_PIPE2 n = pipe2(signal_pipe, O_CLOEXEC | O_NONBLOCK); #else n = pipe(signal_pipe); #endif assert(!n); if (n) log_message(LOG_INFO, "BUG - pipe in signal_handler_init failed (%s), please report", strerror(errno)); #ifndef HAVE_PIPE2 fcntl(signal_pipe[0], F_SETFL, O_NONBLOCK | fcntl(signal_pipe[0], F_GETFL)); fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK | fcntl(signal_pipe[1], F_GETFL)); fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC | fcntl(signal_pipe[0], F_GETFD)); fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC | fcntl(signal_pipe[1], F_GETFD)); #endif signal_SIGHUP_handler = NULL; signal_SIGINT_handler = NULL; signal_SIGTERM_handler = NULL; signal_SIGCHLD_handler = NULL; signal_SIGUSR1_handler = NULL; signal_SIGUSR2_handler = NULL; /* Ignore all signals set to default (except essential ones) */ sigfillset(&sset); sigdelset(&sset, SIGILL); sigdelset(&sset, SIGFPE); sigdelset(&sset, SIGSEGV); sigdelset(&sset, SIGBUS); sigdelset(&sset, SIGKILL); sigdelset(&sset, SIGSTOP); act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (remember) { sigemptyset(&ign_sig); sigemptyset(&dfl_sig); } for (sig = 1; sig <= SIGRTMAX; sig++) { if (sigismember(&sset, sig)){ sigaction(sig, NULL, &oact); /* Remember the original disposition, and ignore * any default action signals */ if (oact.sa_handler == SIG_IGN) { if (remember) sigaddset(&ign_sig, sig); } else { sigaction(sig, &act, NULL); if (remember) sigaddset(&dfl_sig, sig); } } } }
int main(int argc, char *argv[]) { unsigned char msg[MSG_SIZE_RECV]; char pidstr[16]; ssize_t ret; int c, log_method; char *logfile, *pidfile; sigset_t oset, nset; int facility, fd; char *username = NULL; char *chrootdir = NULL; int singleprocess = 0; #ifdef HAVE_GETOPT_LONG int opt_idx; #endif pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0]; srand((unsigned int)time(NULL)); log_method = L_STDERR_SYSLOG; logfile = PATH_RADVD_LOG; conf_file = PATH_RADVD_CONF; facility = LOG_FACILITY; pidfile = PATH_RADVD_PID; /* parse args */ #ifdef HAVE_GETOPT_LONG while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0) #else while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0) #endif { switch (c) { case 'C': conf_file = optarg; break; case 'd': set_debuglevel(atoi(optarg)); break; case 'f': facility = atoi(optarg); break; case 'l': logfile = optarg; break; case 'p': pidfile = optarg; break; case 'm': if (!strcmp(optarg, "syslog")) { log_method = L_SYSLOG; } else if (!strcmp(optarg, "stderr_syslog")) { log_method = L_STDERR_SYSLOG; } else if (!strcmp(optarg, "stderr")) { log_method = L_STDERR; } else if (!strcmp(optarg, "logfile")) { log_method = L_LOGFILE; } else if (!strcmp(optarg, "none")) { log_method = L_NONE; } else { fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg); exit(1); } break; case 't': chrootdir = strdup(optarg); break; case 'u': username = strdup(optarg); break; case 'v': version(); break; case 's': singleprocess = 1; break; case 'h': usage(); #ifdef HAVE_GETOPT_LONG case ':': fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name); exit(1); #endif case '?': exit(1); } } if (chrootdir) { if (!username) { fprintf(stderr, "Chroot as root is not safe, exiting\n"); exit(1); } if (chroot(chrootdir) == -1) { perror("chroot"); exit (1); } if (chdir("/") == -1) { perror("chdir"); exit (1); } /* username will be switched later */ } if (log_open(log_method, pname, logfile, facility) < 0) exit(1); flog(LOG_INFO, "version %s started", VERSION); /* get a raw socket for sending and receiving ICMPv6 messages */ sock = open_icmpv6_socket(); if (sock < 0) exit(1); /* check that 'other' cannot write the file * for non-root, also that self/own group can't either */ if (check_conffile_perm(username, conf_file) < 0) { if (get_debuglevel() == 0) exit(1); else flog(LOG_WARNING, "Insecure file permissions, but continuing anyway"); } /* if we know how to do it, check whether forwarding is enabled */ if (check_ip6_forwarding()) { if (get_debuglevel() == 0) { flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting"); exit(1); } else flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway."); } /* parse config file */ if (readin_config(conf_file) < 0) exit(1); /* drop root privileges if requested. */ if (username) { if (!singleprocess) { dlog(LOG_DEBUG, 3, "Initializing privsep"); if (privsep_init() < 0) flog(LOG_WARNING, "Failed to initialize privsep."); } if (drop_root_privileges(username) < 0) exit(1); } if ((fd = open(pidfile, O_RDONLY, 0)) > 0) { ret = read(fd, pidstr, sizeof(pidstr) - 1); if (ret < 0) { flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno)); exit(1); } pidstr[ret] = '\0'; if (!kill((pid_t)atol(pidstr), 0)) { flog(LOG_ERR, "radvd already running, terminating."); exit(1); } close(fd); fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644); } else /* FIXME: not atomic if pidfile is on an NFS mounted volume */ fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644); if (fd < 0) { flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno)); exit(1); } /* * okay, config file is read in, socket and stuff is setup, so * lets fork now... */ if (get_debuglevel() == 0) { /* Detach from controlling terminal */ if (daemon(0, 0) < 0) perror("daemon"); /* close old logfiles, including stderr */ log_close(); /* reopen logfiles, but don't log to stderr unless explicitly requested */ if (log_method == L_STDERR_SYSLOG) log_method = L_SYSLOG; if (log_open(log_method, pname, logfile, facility) < 0) exit(1); } /* * config signal handlers, also make sure ALRM isn't blocked and raise a warning if so * (some stupid scripts/pppd appears to do this...) */ sigemptyset(&nset); sigaddset(&nset, SIGALRM); sigprocmask(SIG_UNBLOCK, &nset, &oset); if (sigismember(&oset, SIGALRM)) flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong."); signal(SIGHUP, sighup_handler); signal(SIGTERM, sigterm_handler); signal(SIGINT, sigint_handler); snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid()); write(fd, pidstr, strlen(pidstr)); close(fd); config_interface(); kickoff_adverts(); /* enter loop */ for (;;) { int len, hoplimit; struct sockaddr_in6 rcv_addr; struct in6_pktinfo *pkt_info = NULL; len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit); if (len > 0) process(sock, IfaceList, msg, len, &rcv_addr, pkt_info, hoplimit); if (sigterm_received || sigint_received) { stop_adverts(); break; } if (sighup_received) { reload_config(); sighup_received = 0; } } unlink(pidfile); exit(0); }
int main() { sigset_t set,pendset; struct sigaction action1,action2; //initialize the set empty if(sigemptyset(&set)<0) { perror("sigemptyset\n"); exit(1); } if(sigaddset(&set,SIGQUIT)<0) { perror("sigaddset\n"); exit(1); } if(sigaddset(&set,SIGINT)<0) { perror("sigaddset\n"); exit(1); } if(sigismember(&set,SIGINT)) { sigemptyset(&action1.sa_mask); action1.sa_handler=my_func; action1.sa_flags=0; sigaction(SIGINT,&action1,NULL); } if(sigismember(&set,SIGQUIT)) { sigemptyset(&action2.sa_mask); action2.sa_handler=SIG_DFL; action2.sa_flags=0; sigaction(SIGQUIT,&action2,NULL); } if(sigprocmask(SIG_BLOCK,&set,NULL)<0) { perror("sigprocmask"); exit(1); } else { printf("Signal set was blocked,Press any key!\n"); getchar(); } if(sigprocmask(SIG_UNBLOCK,&set,NULL)<0) { perror("sigprocmask"); exit(1); } else { printf("Signal set is in unblock state.\n"); } while(1); exit(0); }
/* * This is the NFS server kernel thread */ static void nfsd(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; struct fs_struct *fsp; int err; struct nfsd_list me; sigset_t shutdown_mask, allowed_mask; /* Lock module and set up kernel thread */ lock_kernel(); daemonize("nfsd"); current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; /* After daemonize() this kernel thread shares current->fs * with the init process. We need to create files with a * umask of 0 instead of init's umask. */ fsp = copy_fs_struct(current->fs); if (!fsp) { printk("Unable to start nfsd thread: out of memory\n"); goto out; } exit_fs(current); current->fs = fsp; current->fs->umask = 0; siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS); siginitsetinv(&allowed_mask, ALLOWED_SIGS); nfsdstats.th_cnt++; lockd_up(); /* start lockd */ me.task = current; list_add(&me.list, &nfsd_list); unlock_kernel(); /* * We want less throttling in balance_dirty_pages() so that nfs to * localhost doesn't cause nfsd to lock up due to all the client's * dirty pages. */ current->flags |= PF_LESS_THROTTLE; /* * The main request loop */ for (;;) { /* Block all but the shutdown signals */ sigprocmask(SIG_SETMASK, &shutdown_mask, NULL); /* * Find a socket with data available and call its * recvfrom routine. */ while ((err = svc_recv(serv, rqstp, 60*60*HZ)) == -EAGAIN) ; if (err < 0) break; update_thread_usage(atomic_read(&nfsd_busy)); atomic_inc(&nfsd_busy); /* Lock the export hash tables for reading. */ exp_readlock(); /* Process request with signals blocked. */ sigprocmask(SIG_SETMASK, &allowed_mask, NULL); svc_process(serv, rqstp); /* Unlock export hash tables */ exp_readunlock(); update_thread_usage(atomic_read(&nfsd_busy)); atomic_dec(&nfsd_busy); } if (err != -EINTR) { printk(KERN_WARNING "nfsd: terminating on error %d\n", -err); } else { unsigned int signo; for (signo = 1; signo <= _NSIG; signo++) if (sigismember(¤t->pending.signal, signo) && !sigismember(¤t->blocked, signo)) break; err = signo; } lock_kernel(); /* Release lockd */ lockd_down(); /* Check if this is last thread */ if (serv->sv_nrthreads==1) { printk(KERN_WARNING "nfsd: last server has exited\n"); if (err != SIG_NOCLEAN) { printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); nfsd_export_flush(); } nfsd_serv = NULL; nfsd_racache_shutdown(); /* release read-ahead cache */ nfs4_state_shutdown(); } list_del(&me.list); nfsdstats.th_cnt --; out: /* Release the thread */ svc_exit_thread(rqstp); /* Release module */ module_put_and_exit(0); }
static int exec_conf(void) { int pipefd[2], stat, size; struct sigaction sa; sigset_t sset, osset; sigemptyset(&sset); sigaddset(&sset, SIGINT); sigprocmask(SIG_BLOCK, &sset, &osset); signal(SIGINT, SIG_DFL); sa.sa_handler = winch_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGWINCH, &sa, NULL); *argptr++ = NULL; pipe(pipefd); pid = fork(); if (pid == 0) { sigprocmask(SIG_SETMASK, &osset, NULL); dup2(pipefd[1], 2); close(pipefd[0]); close(pipefd[1]); execv(args[0], args); _exit(EXIT_FAILURE); } close(pipefd[1]); bufptr = input_buf; while (1) { size = input_buf + sizeof(input_buf) - bufptr; size = read(pipefd[0], bufptr, size); if (size <= 0) { if (size < 0) { if (errno == EINTR || errno == EAGAIN) continue; perror("read"); } break; } bufptr += size; } *bufptr++ = 0; close(pipefd[0]); waitpid(pid, &stat, 0); if (do_resize) { init_wsize(); do_resize = 0; sigprocmask(SIG_SETMASK, &osset, NULL); return -1; } if (WIFSIGNALED(stat)) { printf("\finterrupted(%d)\n", WTERMSIG(stat)); exit(1); } #if 0 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf); sleep(1); #endif sigpending(&sset); if (sigismember(&sset, SIGINT)) { printf("\finterrupted\n"); exit(1); } sigprocmask(SIG_SETMASK, &osset, NULL); return WEXITSTATUS(stat); }
/* Terminate handler */ static void sigend(void *v, int sig) { int status; int ret; int wait_count = 0; sigset_t old_set, child_wait; struct timespec timeout = { .tv_sec = CHILD_WAIT_SECS, .tv_nsec = 0 }; struct timeval start_time, now; /* register the terminate thread */ thread_add_terminate_event(master); log_message(LOG_INFO, "Stopping"); sigprocmask(0, NULL, &old_set); if (!sigismember(&old_set, SIGCHLD)) { sigemptyset(&child_wait); sigaddset(&child_wait, SIGCHLD); sigprocmask(SIG_BLOCK, &child_wait, NULL); } if (vrrp_child > 0) { kill(vrrp_child, SIGTERM); wait_count++; } if (checkers_child > 0) { kill(checkers_child, SIGTERM); wait_count++; } gettimeofday(&start_time, NULL); while (wait_count) { ret = sigtimedwait(&child_wait, NULL, &timeout); if (ret == -1) { if (errno == EINTR) continue; if (errno == EAGAIN) break; } if (vrrp_child > 0 && vrrp_child == waitpid(vrrp_child, &status, WNOHANG)) { report_child_status(status, vrrp_child, PROG_VRRP); wait_count--; } if (checkers_child > 0 && checkers_child == waitpid(checkers_child, &status, WNOHANG)) { report_child_status(status, checkers_child, PROG_CHECK); wait_count--; } if (wait_count) { gettimeofday(&now, NULL); if (now.tv_usec < start_time.tv_usec) { timeout.tv_nsec = (start_time.tv_usec - now.tv_usec) * 1000; timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec); } else if (now.tv_usec == start_time.tv_usec) { timeout.tv_nsec = 0; timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec); } else { timeout.tv_nsec = (1000000L + start_time.tv_usec - now.tv_usec) * 1000; timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec + 1); } timeout.tv_nsec = (start_time.tv_usec - now.tv_usec) * 1000; timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec); if (timeout.tv_nsec < 0) { timeout.tv_nsec += 1000000000L; timeout.tv_sec--; } } } if (!sigismember(&old_set, SIGCHLD)) sigprocmask(SIG_UNBLOCK, &child_wait, NULL); } /* Initialize signal handler */ static void signal_init(void) { signal_handler_init(); signal_set(SIGHUP, propogate_signal, NULL); signal_set(SIGUSR1, propogate_signal, NULL); signal_set(SIGUSR2, propogate_signal, NULL); signal_set(SIGINT, sigend, NULL); signal_set(SIGTERM, sigend, NULL); signal_ignore(SIGPIPE); }
int rpmsqIsCaught(int signum) { return sigismember(&rpmsqCaught, signum); }
int sig_received(FAR _TCB *stcb, siginfo_t *info) { irqstate_t saved_state; int ret = ERROR; sdbg("TCB=0x%08x signo=%d code=%d value=%d mask=%08x\n", stcb, info->si_signo, info->si_code, info->si_value.sival_int, stcb->sigprocmask); if (stcb && info) { ret = OK; /****************** MASKED SIGNAL HANDLING ******************/ /* Check if the signal is masked -- if it is, it will be added to the * list of pending signals. */ if (sigismember(&stcb->sigprocmask, info->si_signo)) { /* Check if the task is waiting for this pending signal. If so, * then unblock it. This must be performed in a critical section * because signals can be queued from the interrupt level. */ saved_state = irqsave(); if (stcb->task_state == TSTATE_WAIT_SIG && sigismember(&stcb->sigwaitmask, info->si_signo)) { memcpy(&stcb->sigunbinfo, info, sizeof(siginfo_t)); stcb->sigwaitmask = NULL_SIGNAL_SET; up_unblock_task(stcb); irqrestore(saved_state); } /* Its not one we are waiting for... Add it to the list of pending * signals. */ else { irqrestore(saved_state); if (!sig_addpendingsignal(stcb, info)) { PANIC(OSERR_FAILEDTOADDSIGNAL); } } } /****************** UNMASKED SIGNAL HANDLING ******************/ else { /* Queue any sigaction's requested by this task. */ ret = sig_queueaction(stcb, info); /* Then schedule execution of the signal handling action on * the recipients thread. */ up_schedule_sigaction(stcb, sig_deliver); /* Check if the task is waiting for an unmasked signal. If so, * then unblock it. This must be performed in a critical section * because signals can be queued from the interrupt level. */ saved_state = irqsave(); if (stcb->task_state == TSTATE_WAIT_SIG) { memcpy(&stcb->sigunbinfo, info, sizeof(siginfo_t)); stcb->sigwaitmask = NULL_SIGNAL_SET; up_unblock_task(stcb); } irqrestore(saved_state); /* If the task neither was waiting for the signal nor had a signal * handler attached to the signal, then the default action is * simply to ignore the signal */ /****************** OTHER SIGNAL HANDLING ******************/ /* If the task is blocked waiting for a semaphore, then that * task must be unblocked when a signal is received. */ if (stcb->task_state == TSTATE_WAIT_SEM) { sem_waitirq(stcb); } /* If the task is blocked waiting on a message queue, then that * task must be unblocked when a signal is received. */ #ifndef CONFIG_DISABLE_MQUEUE if (stcb->task_state == TSTATE_WAIT_MQNOTEMPTY || stcb->task_state == TSTATE_WAIT_MQNOTFULL) { mq_waitirq(stcb); } #endif } } return ret; }
static int group_signal_handler(pid_t pid, FAR void *arg) { FAR struct group_signal_s *info = (FAR struct group_signal_s *)arg; FAR struct tcb_s *tcb; FAR sigactq_t *sigact; int ret; /* Get the TCB associated with the group member */ tcb = sched_gettcb(pid); DEBUGASSERT(tcb != NULL && tcb->group != NULL && info != NULL); if (tcb) { /* Set this one as the default if we have not already set the default. */ if (!info->dtcb) { info->dtcb = tcb; } /* Is the thread waiting for this signal (in this case, the signal is * probably blocked). */ if (sigismember(&tcb->sigwaitmask, info->siginfo->si_signo) && !info->atcb) { /* Yes.. This means that the task is suspended, waiting for this * signal to occur. Stop looking and use this TCB. The * requirement is this: If a task group receives a signal and * more than one thread is waiting on that signal, then one and * only one indeterminate thread out of that waiting group will * receive the signal. */ ret = sig_tcbdispatch(tcb, info->siginfo); if (ret < 0) { return ret; } /* Limit to one thread */ info->atcb = tcb; if (info->ptcb != NULL) { return 1; /* Terminate the search */ } } /* Is this signal unblocked on this thread? */ if (!sigismember(&tcb->sigprocmask, info->siginfo->si_signo) && !info->ptcb && tcb != info->atcb) { /* Yes.. remember this TCB if we have not encountered any * other threads that have the signal unblocked. */ if (!info->utcb) { info->utcb = tcb; } /* Is there also a action associated with the task group? */ sigact = sig_findaction(tcb->group, info->siginfo->si_signo); if (sigact) { /* Yes.. then use this thread. The requirement is this: * If a task group receives a signal then one and only one * indeterminate thread in the task group which is not * blocking the signal will receive the signal. */ ret = sig_tcbdispatch(tcb, info->siginfo); if (ret < 0) { return ret; } /* Limit to one thread */ info->ptcb = tcb; if (info->atcb != NULL) { return 1; /* Terminate the search */ } } } } return 0; /* Keep searching */ }
void lock_mtab (void) { int tries = 3; char linktargetfile[MOUNTLOCK_LINKTARGET_LTH]; at_die = unlock_mtab; if (!signals_have_been_setup) { int sig = 0; struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = 0; sigfillset (&sa.sa_mask); while (sigismember (&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD) { if (sig == SIGALRM) sa.sa_handler = setlkw_timeout; else sa.sa_handler = handler; sigaction (sig, &sa, (struct sigaction *) 0); } signals_have_been_setup = 1; } sprintf(linktargetfile, MOUNTLOCK_LINKTARGET, getpid ()); /* Repeat until it was us who made the link */ while (!we_created_lockfile) { struct flock flock; int errsv, fd, i, j; i = open (linktargetfile, O_WRONLY|O_CREAT, 0); if (i < 0) { int errsv = errno; /* linktargetfile does not exist (as a file) and we cannot create it. Read-only filesystem? Too many files open in the system? Filesystem full? */ die (EX_FILEIO, _("can't create lock file %s: %s " "(use -n flag to override)"), linktargetfile, strerror (errsv)); } close(i); j = link(linktargetfile, MOUNTED_LOCK); errsv = errno; (void) unlink(linktargetfile); if (j == 0) we_created_lockfile = 1; if (j < 0 && errsv != EEXIST) { die (EX_FILEIO, _("can't link lock file %s: %s " "(use -n flag to override)"), MOUNTED_LOCK, strerror (errsv)); } fd = open (MOUNTED_LOCK, O_WRONLY); if (fd < 0) { int errsv = errno; /* Strange... Maybe the file was just deleted? */ if (errno == ENOENT && tries-- > 0) continue; die (EX_FILEIO, _("can't open lock file %s: %s " "(use -n flag to override)"), MOUNTED_LOCK, strerror (errsv)); } flock.l_type = F_WRLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; if (j == 0) { /* We made the link. Now claim the lock. */ if (fcntl (fd, F_SETLK, &flock) == -1) { if (verbose) { int errsv = errno; printf(_("Can't lock lock file %s: %s\n"), MOUNTED_LOCK, strerror (errsv)); } /* proceed anyway */ } } else { static int tries = 0; /* Someone else made the link. Wait. */ alarm(LOCK_TIMEOUT); if (fcntl (fd, F_SETLKW, &flock) == -1) { int errsv = errno; die (EX_FILEIO, _("can't lock lock file %s: %s"), MOUNTED_LOCK, (errno == EINTR) ? _("timed out") : strerror (errsv)); } alarm(0); /* Limit the number of iterations - maybe there still is some old /etc/mtab~ */ if (tries++ > 3) { if (tries > 5) die (EX_FILEIO, _("Cannot create link %s\n" "Perhaps there is a stale lock file?\n"), MOUNTED_LOCK); sleep(1); } } close(fd); } }
/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. * * Note that we go through the signals twice: once to check the signals that * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ int do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; struct k_sigaction *ka; /* * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so. */ if (!user_mode(regs)) return 1; if (!oldset) oldset = ¤t->blocked; for (;;) { unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) continue; current->exit_code = 0; /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) continue; /* Update the siginfo structure. Is this good? */ if (signr != info.si_signo) { info.si_signo = signr; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, &info, current); continue; } } ka = ¤t->sig->action[signr-1]; if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; /* Check for SIGCHLD: it's special. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; /* FALLTHRU */ case SIGSTOP: current->state = TASK_STOPPED; current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); return 1; } /* Did we come from a system call? */ if (regs->syscall_nr >= 0) { /* Restart the system call - no handlers present */ if (regs->regs[0] == -ERESTARTNOHAND || regs->regs[0] == -ERESTARTSYS || regs->regs[0] == -ERESTARTNOINTR) { regs->regs[0] = regs->syscall_nr; regs->pc -= 2; } } return 0; }
int is_ignored(int sig) { return (sigismember(¤t->blocked, sig) || current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); }
/* * Note that `init' is a special process: it doesn't get signals it doesn't want to * handle. Thus you cannot kill init even with a SIGKILL even by mistake. */ long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) { struct signal_struct *sig; struct k_sigaction *ka; siginfo_t info; long restart = in_syscall; long errno = scr->pt.r8; /* * In the ia64_leave_kernel code path, we want the common case to go fast, which * is why we may in certain cases get here from kernel mode. Just return without * doing anything if so. */ if (!user_mode(&scr->pt)) return 0; if (!oldset) oldset = ¤t->blocked; #ifdef CONFIG_IA32_SUPPORT if (IS_IA32_PROCESS(&scr->pt)) { if (in_syscall) { if (errno >= 0) restart = 0; else errno = -errno; } } else #endif if (scr->pt.r10 != -1) { /* * A system calls has to be restarted only if one of the error codes * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned. If r10 * isn't -1 then r8 doesn't hold an error code and we don't need to * restart the syscall, so we can clear the "restart" flag here. */ restart = 0; } for (;;) { unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->thread.siginfo = &info; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); signr = current->exit_code; current->thread.siginfo = 0; /* We're back. Did the debugger cancel the sig? */ if (!signr) continue; current->exit_code = 0; /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) continue; /* Update the siginfo structure. Is this good? */ if (signr != info.si_signo) { info.si_signo = signr; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, &info, current); continue; } } ka = ¤t->sig->action[signr - 1]; if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; /* Check for SIGCHLD: it's special. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; /* FALLTHRU */ case SIGSTOP: current->state = TASK_STOPPED; current->exit_code = signr; sig = current->p_pptr->sig; if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, &scr->pt)) exit_code |= 0x80; /* FALLTHRU */ default: sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ } } if (restart) { switch (errno) { case ERESTARTSYS: if ((ka->sa.sa_flags & SA_RESTART) == 0) { case ERESTARTNOHAND: #ifdef CONFIG_IA32_SUPPORT if (IS_IA32_PROCESS(&scr->pt)) scr->pt.r8 = -EINTR; else #endif scr->pt.r8 = EINTR; /* note: scr->pt.r10 is already -1 */ break; } case ERESTARTNOINTR: #ifdef CONFIG_IA32_SUPPORT if (IS_IA32_PROCESS(&scr->pt)) { scr->pt.r8 = scr->pt.r1; scr->pt.cr_iip -= 2; } else #endif ia64_decrement_ip(&scr->pt); } } /* Whee! Actually deliver the signal. If the delivery failed, we need to continue to iterate in this loop so we can deliver the SIGSEGV... */ if (handle_signal(signr, ka, &info, oldset, scr)) return 1; } /* Did we come from a system call? */ if (restart) { /* Restart the system call - no handlers present */ if (errno == ERESTARTNOHAND || errno == ERESTARTSYS || errno == ERESTARTNOINTR) { #ifdef CONFIG_IA32_SUPPORT if (IS_IA32_PROCESS(&scr->pt)) { scr->pt.r8 = scr->pt.r1; scr->pt.cr_iip -= 2; } else #endif /* * Note: the syscall number is in r15 which is * saved in pt_regs so all we need to do here * is adjust ip so that the "break" * instruction gets re-executed. */ ia64_decrement_ip(&scr->pt); } } return 0; }
/* the heart of this library: the thread scheduler */ intern void *pth_scheduler(void *dummy) { sigset_t sigs; pth_time_t running; pth_time_t snapshot; struct sigaction sa; sigset_t ss; int sig; pth_t t; /* * bootstrapping */ pth_debug1("pth_scheduler: bootstrapping"); /* mark this thread as the special scheduler thread */ pth_sched->state = PTH_STATE_SCHEDULER; /* block all signals in the scheduler thread */ sigfillset(&sigs); pth_sc(sigprocmask)(SIG_SETMASK, &sigs, NULL); /* initialize the snapshot time for bootstrapping the loop */ pth_time_set(&snapshot, PTH_TIME_NOW); /* * endless scheduler loop */ for (;;) { /* * Move threads from new queue to ready queue and optionally * give them maximum priority so they start immediately. */ while ((t = pth_pqueue_tail(&pth_NQ)) != NULL) { pth_pqueue_delete(&pth_NQ, t); t->state = PTH_STATE_READY; if (pth_favournew) pth_pqueue_insert(&pth_RQ, pth_pqueue_favorite_prio(&pth_RQ), t); else pth_pqueue_insert(&pth_RQ, PTH_PRIO_STD, t); pth_debug2("pth_scheduler: new thread \"%s\" moved to top of ready queue", t->name); } /* Calculate thread target runtime for ready queue */ pth_pqueue_calc_target(&pth_RQ); /* Assign tikets to threads in ready queue */ pth_pqueue_issue_tk(&pth_RQ); /* * Update average scheduler load */ pth_scheduler_load(&snapshot); /* * Find next thread in ready queue */ /* generate lottery number randomly */ /* pth_current = pth_pqueue_delmax(&pth_RQ); */ int ltr_num = rand() % pth_RQ.total_tk; pth_current = pth_pqueue_deltk(&pth_RQ, ltr_num); if (pth_current == NULL) { fprintf(stderr, "**Pth** SCHEDULER INTERNAL ERROR: " "no more thread(s) available to schedule!?!?\n"); abort(); } pth_debug4("pth_scheduler: thread \"%s\" selected (prio=%d, qprio=%d)", pth_current->name, pth_current->prio, pth_current->q_prio); /* * Raise additionally thread-specific signals * (they are delivered when we switch the context) * * Situation is ('#' = signal pending): * process pending (pth_sigpending): ----#### * thread pending (pth_current->sigpending): --##--## * Result has to be: * process new pending: --###### */ if (pth_current->sigpendcnt > 0) { sigpending(&pth_sigpending); for (sig = 1; sig < PTH_NSIG; sig++) if (sigismember(&pth_current->sigpending, sig)) if (!sigismember(&pth_sigpending, sig)) kill(getpid(), sig); } /* * Set running start time for new thread * and perform a context switch to it */ pth_debug3("pth_scheduler: switching to thread 0x%lx (\"%s\")", (unsigned long)pth_current, pth_current->name); /* update thread times */ pth_time_set(&pth_current->lastran, PTH_TIME_NOW); /* update scheduler times */ pth_time_set(&running, &pth_current->lastran); pth_time_sub(&running, &snapshot); pth_time_add(&pth_sched->running, &running); /* ** ENTERING THREAD ** - by switching the machine context */ pth_current->dispatches++; pth_mctx_switch(&pth_sched->mctx, &pth_current->mctx); /* update scheduler times */ pth_time_set(&snapshot, PTH_TIME_NOW); pth_debug3("pth_scheduler: cameback from thread 0x%lx (\"%s\")", (unsigned long)pth_current, pth_current->name); /* * Calculate and update the time the previous thread was running */ pth_time_set(&running, &snapshot); pth_time_sub(&running, &pth_current->lastran); pth_time_add(&pth_current->running, &running); /* Update actual time of all threads in ready queue */ pth_pqueue_update_a_rt(&pth_RQ); pth_debug3("pth_scheduler: thread \"%s\" ran %.6f", pth_current->name, pth_time_t2d(&running)); /* Additional debugging code */ pth_debug2("pth_scheduler: lottery number %d", ltr_num); pth_debug2("pth_scheduler: total ticket %d", pth_RQ.total_tk); pth_debug3("pth_scheduler: thread has %d offset and %d tickets", (pth_current->tk).offset, (pth_current->tk).tk_num); pth_debug3("pth_scheduler: thread has %.6f running time and %.6f lifetime", pth_time_t2d(&pth_current->running), pth_time_t2d(&lifetime)); pth_debug2("pth_scheduler: thread has %.6f target runtime", (pth_current->cpu_rt).target); pth_debug2("pth_scheduler: thread has %.6f actual runtime", (pth_current->cpu_rt).actual); /* * Remove still pending thread-specific signals * (they are re-delivered next time) * * Situation is ('#' = signal pending): * thread old pending (pth_current->sigpending): --##--## * process old pending (pth_sigpending): ----#### * process still pending (sigstillpending): ---#-#-# * Result has to be: * process new pending: -----#-# * thread new pending (pth_current->sigpending): ---#---# */ if (pth_current->sigpendcnt > 0) { sigset_t sigstillpending; sigpending(&sigstillpending); for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(&pth_current->sigpending, sig)) { if (!sigismember(&sigstillpending, sig)) { /* thread (and perhaps also process) signal delivered */ sigdelset(&pth_current->sigpending, sig); pth_current->sigpendcnt--; } else if (!sigismember(&pth_sigpending, sig)) { /* thread signal not delivered */ pth_util_sigdelete(sig); } } } } /* * Check for stack overflow */ if (pth_current->stackguard != NULL) { if (*pth_current->stackguard != 0xDEAD) { pth_debug3("pth_scheduler: stack overflow detected for thread 0x%lx (\"%s\")", (unsigned long)pth_current, pth_current->name); /* * if the application doesn't catch SIGSEGVs, we terminate * manually with a SIGSEGV now, but output a reasonable message. */ if (sigaction(SIGSEGV, NULL, &sa) == 0) { if (sa.sa_handler == SIG_DFL) { fprintf(stderr, "**Pth** STACK OVERFLOW: thread pid_t=0x%lx, name=\"%s\"\n", (unsigned long)pth_current, pth_current->name); kill(getpid(), SIGSEGV); sigfillset(&ss); sigdelset(&ss, SIGSEGV); sigsuspend(&ss); abort(); } } /* * else we terminate the thread only and send us a SIGSEGV * which allows the application to handle the situation... */ pth_current->join_arg = (void *)0xDEAD; pth_current->state = PTH_STATE_DEAD; kill(getpid(), SIGSEGV); } } /* * If previous thread is now marked as dead, kick it out */ if (pth_current->state == PTH_STATE_DEAD) { pth_debug2("pth_scheduler: marking thread \"%s\" as dead", pth_current->name); if (!pth_current->joinable) pth_tcb_free(pth_current); else pth_pqueue_insert(&pth_DQ, PTH_PRIO_STD, pth_current); pth_current = NULL; } /* * If thread wants to wait for an event * move it to waiting queue now */ if (pth_current != NULL && pth_current->state == PTH_STATE_WAITING) { pth_debug2("pth_scheduler: moving thread \"%s\" to waiting queue", pth_current->name); pth_pqueue_insert(&pth_WQ, pth_current->prio, pth_current); pth_current = NULL; } /* * migrate old treads in ready queue into higher * priorities to avoid starvation and insert last running * thread back into this queue, too. */ /* Disable this auto-increment mechanism */ /* pth_pqueue_increase(&pth_RQ); */ if (pth_current != NULL) pth_pqueue_insert(&pth_RQ, pth_current->prio, pth_current); /* * Manage the events in the waiting queue, i.e. decide whether their * events occurred and move them to the ready queue. But wait only if * we have already no new or ready threads. */ if ( pth_pqueue_elements(&pth_RQ) == 0 && pth_pqueue_elements(&pth_NQ) == 0) /* still no NEW or READY threads, so we have to wait for new work */ pth_sched_eventmanager(&snapshot, FALSE /* wait */); else /* already NEW or READY threads exists, so just poll for even more work */ pth_sched_eventmanager(&snapshot, TRUE /* poll */); } /* NOTREACHED */ return NULL; }
char * print_arg(struct syscall_args *sc, unsigned long *args, long retval, struct trussinfo *trussinfo) { char *tmp; pid_t pid; tmp = NULL; pid = trussinfo->pid; switch (sc->type & ARG_MASK) { case Hex: asprintf(&tmp, "0x%x", (int)args[sc->offset]); break; case Octal: asprintf(&tmp, "0%o", (int)args[sc->offset]); break; case Int: asprintf(&tmp, "%d", (int)args[sc->offset]); break; case Name: { /* NULL-terminated string. */ char *tmp2; tmp2 = get_string(pid, (void*)args[sc->offset], 0); asprintf(&tmp, "\"%s\"", tmp2); free(tmp2); break; } case BinString: { /* Binary block of data that might have printable characters. XXX If type|OUT, assume that the length is the syscall's return value. Otherwise, assume that the length of the block is in the next syscall argument. */ int max_string = trussinfo->strsize; char tmp2[max_string+1], *tmp3; int len; int truncated = 0; if (sc->type & OUT) len = retval; else len = args[sc->offset + 1]; /* Don't print more than max_string characters, to avoid word wrap. If we have to truncate put some ... after the string. */ if (len > max_string) { len = max_string; truncated = 1; } if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) != -1) { tmp3 = malloc(len * 4 + 1); while (len) { if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) break; len--; truncated = 1; }; asprintf(&tmp, "\"%s\"%s", tmp3, truncated ? "..." : ""); free(tmp3); } else { asprintf(&tmp, "0x%lx", args[sc->offset]); } break; } case StringArray: { int num, size, i; char *tmp2; char *string; char *strarray[100]; /* XXX This is ugly. */ if (get_struct(pid, (void *)args[sc->offset], (void *)&strarray, sizeof(strarray)) == -1) err(1, "get_struct %p", (void *)args[sc->offset]); num = 0; size = 0; /* Find out how large of a buffer we'll need. */ while (strarray[num] != NULL) { string = get_string(pid, (void*)strarray[num], 0); size += strlen(string); free(string); num++; } size += 4 + (num * 4); tmp = (char *)malloc(size); tmp2 = tmp; tmp2 += sprintf(tmp2, " ["); for (i = 0; i < num; i++) { string = get_string(pid, (void*)strarray[i], 0); tmp2 += sprintf(tmp2, " \"%s\"%c", string, (i + 1 == num) ? ' ' : ','); free(string); } tmp2 += sprintf(tmp2, "]"); break; } #ifdef __LP64__ case Quad: asprintf(&tmp, "0x%lx", args[sc->offset]); break; #else case Quad: { unsigned long long ll; ll = *(unsigned long long *)(args + sc->offset); asprintf(&tmp, "0x%llx", ll); break; } #endif case Ptr: asprintf(&tmp, "0x%lx", args[sc->offset]); break; case Readlinkres: { char *tmp2; if (retval == -1) { tmp = strdup(""); break; } tmp2 = get_string(pid, (void*)args[sc->offset], retval); asprintf(&tmp, "\"%s\"", tmp2); free(tmp2); break; } case Ioctl: { const char *temp = ioctlname(args[sc->offset]); if (temp) tmp = strdup(temp); else { unsigned long arg = args[sc->offset]; asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", arg, arg & IOC_OUT ? "R" : "", arg & IOC_IN ? "W" : "", IOCGROUP(arg), isprint(IOCGROUP(arg)) ? (char)IOCGROUP(arg) : '?', arg & 0xFF, IOCPARM_LEN(arg)); } break; } case Umtx: { struct umtx umtx; if (get_struct(pid, (void *)args[sc->offset], &umtx, sizeof(umtx)) != -1) asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner); else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case Timespec: { struct timespec ts; if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) != -1) asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec, ts.tv_nsec); else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case Timeval: { struct timeval tv; if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec, tv.tv_usec); else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case Timeval2: { struct timeval tv[2]; if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", (long)tv[0].tv_sec, tv[0].tv_usec, (long)tv[1].tv_sec, tv[1].tv_usec); else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case Itimerval: { struct itimerval itv; if (get_struct(pid, (void *)args[sc->offset], &itv, sizeof(itv)) != -1) asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", (long)itv.it_interval.tv_sec, itv.it_interval.tv_usec, (long)itv.it_value.tv_sec, itv.it_value.tv_usec); else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case LinuxSockArgs: { struct linux_socketcall_args largs; if (get_struct(pid, (void *)args[sc->offset], (void *)&largs, sizeof(largs)) == -1) { err(1, "get_struct %p", (void *)args[sc->offset]); } const char *what; char buf[30]; switch (largs.what) { case LINUX_SOCKET: what = "LINUX_SOCKET"; break; case LINUX_BIND: what = "LINUX_BIND"; break; case LINUX_CONNECT: what = "LINUX_CONNECT"; break; case LINUX_LISTEN: what = "LINUX_LISTEN"; break; case LINUX_ACCEPT: what = "LINUX_ACCEPT"; break; case LINUX_GETSOCKNAME: what = "LINUX_GETSOCKNAME"; break; case LINUX_GETPEERNAME: what = "LINUX_GETPEERNAME"; break; case LINUX_SOCKETPAIR: what = "LINUX_SOCKETPAIR"; break; case LINUX_SEND: what = "LINUX_SEND"; break; case LINUX_RECV: what = "LINUX_RECV"; break; case LINUX_SENDTO: what = "LINUX_SENDTO"; break; case LINUX_RECVFROM: what = "LINUX_RECVFROM"; break; case LINUX_SHUTDOWN: what = "LINUX_SHUTDOWN"; break; case LINUX_SETSOCKOPT: what = "LINUX_SETSOCKOPT"; break; case LINUX_GETSOCKOPT: what = "LINUX_GETSOCKOPT"; break; case LINUX_SENDMSG: what = "LINUX_SENDMSG"; break; case LINUX_RECVMSG: what = "LINUX_RECVMSG"; break; default: sprintf(buf, "%d", largs.what); what = buf; break; } asprintf(&tmp, "(0x%lx)%s, 0x%lx", args[sc->offset], what, (long unsigned int)largs.args); break; } case Pollfd: { /* * XXX: A Pollfd argument expects the /next/ syscall argument * to be the number of fds in the array. This matches the poll * syscall. */ struct pollfd *pfd; int numfds = args[sc->offset+1]; int bytes = sizeof(struct pollfd) * numfds; int i, tmpsize, u, used; const int per_fd = 100; if ((pfd = malloc(bytes)) == NULL) err(1, "Cannot malloc %d bytes for pollfd array", bytes); if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) != -1) { used = 0; tmpsize = 1 + per_fd * numfds + 2; if ((tmp = malloc(tmpsize)) == NULL) err(1, "Cannot alloc %d bytes for poll output", tmpsize); tmp[used++] = '{'; for (i = 0; i < numfds; i++) { u = snprintf(tmp + used, per_fd, "%s%d/%s", i > 0 ? " " : "", pfd[i].fd, xlookup_bits(poll_flags, pfd[i].events)); if (u > 0) used += u < per_fd ? u : per_fd; } tmp[used++] = '}'; tmp[used++] = '\0'; } else { asprintf(&tmp, "0x%lx", args[sc->offset]); } free(pfd); break; } case Fd_set: { /* * XXX: A Fd_set argument expects the /first/ syscall argument * to be the number of fds in the array. This matches the * select syscall. */ fd_set *fds; int numfds = args[0]; int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; int i, tmpsize, u, used; const int per_fd = 20; if ((fds = malloc(bytes)) == NULL) err(1, "Cannot malloc %d bytes for fd_set array", bytes); if (get_struct(pid, (void *)args[sc->offset], fds, bytes) != -1) { used = 0; tmpsize = 1 + numfds * per_fd + 2; if ((tmp = malloc(tmpsize)) == NULL) err(1, "Cannot alloc %d bytes for fd_set " "output", tmpsize); tmp[used++] = '{'; for (i = 0; i < numfds; i++) { if (FD_ISSET(i, fds)) { u = snprintf(tmp + used, per_fd, "%d ", i); if (u > 0) used += u < per_fd ? u : per_fd; } } if (tmp[used-1] == ' ') used--; tmp[used++] = '}'; tmp[used++] = '\0'; } else asprintf(&tmp, "0x%lx", args[sc->offset]); free(fds); break; } case Signal: tmp = strsig2(args[sc->offset]); break; case Sigset: { long sig; sigset_t ss; int i, used; char *signame; sig = args[sc->offset]; if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, sizeof(ss)) == -1) { asprintf(&tmp, "0x%lx", args[sc->offset]); break; } tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */ used = 0; for (i = 1; i < sys_nsig; i++) { if (sigismember(&ss, i)) { signame = strsig(i); used += sprintf(tmp + used, "%s|", signame); free(signame); } } if (used) tmp[used-1] = 0; else strcpy(tmp, "0x0"); break; } case Sigprocmask: { switch (args[sc->offset]) { #define S(a) case a: tmp = strdup(#a); break; S(SIG_BLOCK); S(SIG_UNBLOCK); S(SIG_SETMASK); #undef S } if (tmp == NULL) asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case Fcntlflag: { /* XXX output depends on the value of the previous argument */ switch (args[sc->offset-1]) { case F_SETFD: tmp = strdup(xlookup_bits(fcntlfd_arg, args[sc->offset])); break; case F_SETFL: tmp = strdup(xlookup_bits(fcntlfl_arg, args[sc->offset])); break; case F_GETFD: case F_GETFL: case F_GETOWN: tmp = strdup(""); break; default: asprintf(&tmp, "0x%lx", args[sc->offset]); break; } break; } case Open: tmp = strdup(xlookup_bits(open_flags, args[sc->offset])); break; case Fcntl: tmp = strdup(xlookup(fcntl_arg, args[sc->offset])); break; case Mprot: tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset])); break; case Mmapflags: { char *base, *alignstr; int align, flags; /* * MAP_ALIGNED can't be handled by xlookup_bits(), so * generate that string manually and prepend it to the * string from xlookup_bits(). Have to be careful to * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is * the only flag. */ flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK; align = args[sc->offset] & MAP_ALIGNMENT_MASK; if (align != 0) { if (align == MAP_ALIGNED_SUPER) alignstr = strdup("MAP_ALIGNED_SUPER"); else asprintf(&alignstr, "MAP_ALIGNED(%d)", align >> MAP_ALIGNMENT_SHIFT); if (flags == 0) { tmp = alignstr; break; } } else alignstr = NULL; base = strdup(xlookup_bits(mmap_flags, flags)); if (alignstr == NULL) { tmp = base; break; } asprintf(&tmp, "%s|%s", alignstr, base); free(alignstr); free(base); break; } case Whence: tmp = strdup(xlookup(whence_arg, args[sc->offset])); break; case Sockdomain: tmp = strdup(xlookup(sockdomain_arg, args[sc->offset])); break; case Socktype: tmp = strdup(xlookup(socktype_arg, args[sc->offset])); break; case Shutdown: tmp = strdup(xlookup(shutdown_arg, args[sc->offset])); break; case Resource: tmp = strdup(xlookup(resource_arg, args[sc->offset])); break; case Pathconf: tmp = strdup(xlookup(pathconf_arg, args[sc->offset])); break; case Rforkflags: tmp = strdup(xlookup_bits(rfork_flags, args[sc->offset])); break; case Sockaddr: { struct sockaddr_storage ss; char addr[64]; struct sockaddr_in *lsin; struct sockaddr_in6 *lsin6; struct sockaddr_un *sun; struct sockaddr *sa; char *p; u_char *q; int i; if (args[sc->offset] == 0) { asprintf(&tmp, "NULL"); break; } /* yuck: get ss_len */ if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) err(1, "get_struct %p", (void *)args[sc->offset]); /* * If ss_len is 0, then try to guess from the sockaddr type. * AF_UNIX may be initialized incorrectly, so always frob * it by using the "right" size. */ if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { switch (ss.ss_family) { case AF_INET: ss.ss_len = sizeof(*lsin); break; case AF_UNIX: ss.ss_len = sizeof(*sun); break; default: /* hurrrr */ break; } } if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, ss.ss_len) == -1) { err(2, "get_struct %p", (void *)args[sc->offset]); } switch (ss.ss_family) { case AF_INET: lsin = (struct sockaddr_in *)&ss; inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); break; case AF_INET6: lsin6 = (struct sockaddr_in6 *)&ss; inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr); asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); break; case AF_UNIX: sun = (struct sockaddr_un *)&ss; asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); break; default: sa = (struct sockaddr *)&ss; asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data " "= {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family, &i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), ""); if (tmp != NULL) { p = tmp + i; for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++) p += sprintf(p, " %#02x,", *q); } } break; } case Sigaction: { struct sigaction sa; char *hand; const char *h; if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) { asprintf(&hand, "%p", sa.sa_handler); if (sa.sa_handler == SIG_DFL) h = "SIG_DFL"; else if (sa.sa_handler == SIG_IGN) h = "SIG_IGN"; else h = hand; asprintf(&tmp, "{ %s %s ss_t }", h, xlookup_bits(sigaction_flags, sa.sa_flags)); free(hand); } else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case Kevent: { /* * XXX XXX: the size of the array is determined by either the * next syscall argument, or by the syscall returnvalue, * depending on which argument number we are. This matches the * kevent syscall, but luckily that's the only syscall that uses * them. */ struct kevent *ke; int numevents = -1; int bytes = 0; int i, tmpsize, u, used; const int per_ke = 100; if (sc->offset == 1) numevents = args[sc->offset+1]; else if (sc->offset == 3 && retval != -1) numevents = retval; if (numevents >= 0) bytes = sizeof(struct kevent) * numevents; if ((ke = malloc(bytes)) == NULL) err(1, "Cannot malloc %d bytes for kevent array", bytes); if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], ke, bytes) != -1) { used = 0; tmpsize = 1 + per_ke * numevents + 2; if ((tmp = malloc(tmpsize)) == NULL) err(1, "Cannot alloc %d bytes for kevent " "output", tmpsize); tmp[used++] = '{'; for (i = 0; i < numevents; i++) { u = snprintf(tmp + used, per_ke, "%s%p,%s,%s,%d,%p,%p", i > 0 ? " " : "", (void *)ke[i].ident, xlookup(kevent_filters, ke[i].filter), xlookup_bits(kevent_flags, ke[i].flags), ke[i].fflags, (void *)ke[i].data, (void *)ke[i].udata); if (u > 0) used += u < per_ke ? u : per_ke; } tmp[used++] = '}'; tmp[used++] = '\0'; } else { asprintf(&tmp, "0x%lx", args[sc->offset]); } free(ke); break; } case Stat: { struct stat st; if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) != -1) { char mode[12]; strmode(st.st_mode, mode); asprintf(&tmp, "{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", mode, (intmax_t)st.st_ino, (intmax_t)st.st_size, (long)st.st_blksize); } else { asprintf(&tmp, "0x%lx", args[sc->offset]); } break; } case Rusage: { struct rusage ru; if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) != -1) { asprintf(&tmp, "{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }", (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, ru.ru_inblock, ru.ru_oublock); } else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case Rlimit: { struct rlimit rl; if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) != -1) { asprintf(&tmp, "{ cur=%ju,max=%ju }", rl.rlim_cur, rl.rlim_max); } else asprintf(&tmp, "0x%lx", args[sc->offset]); break; } case ExitStatus: { char *signame; int status; signame = NULL; if (get_struct(pid, (void *)args[sc->offset], &status, sizeof(status)) != -1) { if (WIFCONTINUED(status)) tmp = strdup("{ CONTINUED }"); else if (WIFEXITED(status)) asprintf(&tmp, "{ EXITED,val=%d }", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) asprintf(&tmp, "{ SIGNALED,sig=%s%s }", signame = strsig2(WTERMSIG(status)), WCOREDUMP(status) ? ",cored" : ""); else asprintf(&tmp, "{ STOPPED,sig=%s }", signame = strsig2(WTERMSIG(status))); } else asprintf(&tmp, "0x%lx", args[sc->offset]); free(signame); break; } case Waitoptions: tmp = strdup(xlookup_bits(wait_options, args[sc->offset])); break; case Idtype: tmp = strdup(xlookup(idtype_arg, args[sc->offset])); break; case Procctl: tmp = strdup(xlookup(procctl_arg, args[sc->offset])); break; default: errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); }
/* Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) { unsigned long signr; siginfo_t info; struct k_sigaction *ka; if (!oldset) oldset = ¤t->blocked; #ifdef CONFIG_SPARC32_COMPAT if (current->thread.flags & SPARC_FLAG_32BIT) { extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *, unsigned long, int); return do_signal32(oldset, regs, orig_i0, restart_syscall); } #endif for (;;) { spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Do the syscall restart before we let the debugger * look at the child registers. */ if (restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { regs->u_regs[UREG_I0] = orig_i0; regs->tpc -= 4; regs->tnpc -= 4; restart_syscall = 0; } current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); if (!(signr = current->exit_code)) continue; current->exit_code = 0; if (signr == SIGSTOP) continue; /* Update the siginfo structure. Is this good? */ if (signr != info.si_signo) { info.si_signo = signr; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, &info, current); continue; } } ka = ¤t->sig->action[signr-1]; if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; /* sys_wait4() grabs the master kernel lock, so * we need not do so, that sucker should be * threaded and would not be that difficult to * do anyways. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) ; continue; } if (ka->sa.sa_handler == SIG_DFL) { unsigned long exit_code = signr; if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; case SIGSTOP: if (current->ptrace & PT_PTRACED) continue; current->state = TASK_STOPPED; current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; #ifdef DEBUG_SIGNALS /* Very useful to debug the dynamic linker */ printk ("Sig %d going...\n", (int)signr); show_regs (regs); #ifdef DEBUG_SIGNALS_TRACE { struct reg_window *rw = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); unsigned long ins[8]; while (rw && !(((unsigned long) rw) & 0x3)) { copy_from_user(ins, &rw->ins[0], sizeof(ins)); printk("Caller[%016lx](%016lx,%016lx,%016lx,%016lx,%016lx,%016lx)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]); rw = (struct reg_window *)(unsigned long)(ins[6] + STACK_BIAS); } } #endif #ifdef DEBUG_SIGNALS_MAPS printk("Maps:\n"); read_maps(); #endif #endif /* fall through */ default: sig_exit(signr, exit_code, &info); /* NOT REACHED */ } } if (restart_syscall) syscall_restart(orig_i0, regs, &ka->sa); handle_signal(signr, ka, &info, oldset, regs); return 1; } if (restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { /* replay the system call when we are done */ regs->u_regs[UREG_I0] = orig_i0; regs->tpc -= 4; regs->tnpc -= 4; } return 0; }
/* Set up all the radvd internal stuff from our own configuration */ int radvd_init(char *ifname, struct config *c) { struct AdvPrefix *prefix; sigset_t oset, nset; if (log_open(L_STDERR, "radvd", NULL, -1) < 0) { error("log_open\n"); return -1; } srand((unsigned int)time(NULL)); info("starting radvd on device %s\n", ifname); sock = open_icmpv6_socket(); if (sock < 0) { error("open_icmpv6_socket\n"); return -1; } sigemptyset(&nset); sigaddset(&nset, SIGALRM); sigprocmask(SIG_UNBLOCK, &nset, &oset); if (sigismember(&oset, SIGALRM)) flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong."); /* setup the radvd struct Interface to know about all our defaults */ iface = malloc(sizeof(struct Interface)); if (iface == NULL) return -1; iface_init_defaults(iface); strncpy(iface->Name, ifname, IFNAMSIZ-1); iface->Name[IFNAMSIZ-1] = '\0'; iface->next = NULL; iface->AdvSendAdvert = 1; /* check the interface exists... this probably shouldn't fail */ if (check_device(sock, iface) < 0) { error("check_device!\n"); return -1; } if (setup_deviceinfo(sock, iface) < 0) { error("setup_deviceinfo\n"); return -1; } if (check_iface(iface) < 0) { error("check_iface\n"); return -1; } if (setup_linklocal_addr(sock, iface) < 0) { error("setup_linklocal_addr\n"); return -1; } if (setup_allrouters_membership(sock, iface) < 0) { error("setup_allrouters_membership\n"); return -1; } /* set up the prefix we're advertising from the config struct we get passed in. */ prefix = malloc(sizeof(struct AdvPrefix)); if (prefix == NULL) return -1; prefix_init_defaults(prefix); prefix->PrefixLen = 64; memcpy(&prefix->Prefix, c->router_addr.s6_addr, sizeof(struct in6_addr)); prefix->next = NULL; iface->AdvPrefixList = prefix; // config_interface(); radvd_kickoff_adverts(); set_debuglevel(0); return sock; }