int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *oact) { FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; FAR sigactq_t *sigact; /* Since sigactions can only be installed from the running thread of * execution, no special precautions should be necessary. */ /* Verify the signal number */ if (!GOOD_SIGNO(signo)) { set_errno(EINVAL); return ERROR; } /* Find the signal in the sigactionq */ sigact = sig_findaction(rtcb, signo); /* Return the old sigaction value if so requested */ if (oact) { if (sigact) { COPY_SIGACTION(oact, &sigact->act); } else { /* There isn't an old value */ oact->sa_u._sa_handler = NULL; oact->sa_mask = NULL_SIGNAL_SET; oact->sa_flags = 0; } } /* If the argument act is a null pointer, signal handling is unchanged; * thus, the call can be used to enquire about the current handling of * a given signal. */ if (!act) { return OK; } #if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS) /* Handle a special case. Retention of child status can be suppressed * if signo == SIGCHLD and sa_flags == SA_NOCLDWAIT. * * POSIX.1 leaves it unspecified whether a SIGCHLD signal is generated * when a child process terminates. In NuttX, a SIGCHLD signal is * generated in this case; but in some other implementations, it may not * be. */ if (signo == SIGCHLD && (act->sa_flags & SA_NOCLDWAIT) != 0) { irqstate_t flags; /* We do require a critical section to muck with the TCB values that * can be modified by the child thread. */ flags = irqsave(); /* Mark that status should be not be retained */ rtcb->group->tg_flags |= GROUP_FLAG_NOCLDWAIT; /* Free all pending exit status */ group_removechildren(rtcb->group); irqrestore(flags); } #endif /* Handle the case where no sigaction is supplied (SIG_IGN) */ if (act->sa_u._sa_handler == SIG_IGN) { /* Do we still have a sigaction container from the previous setting? */ if (sigact) { /* Yes.. Remove it from sigactionq */ sq_rem((FAR sq_entry_t*)sigact, &rtcb->sigactionq); /* And deallocate it */ sig_releaseaction(sigact); } } /* A sigaction has been supplied */ else { /* Do we still have a sigaction container from the previous setting? * If so, then re-use for the new signal action. */ if (!sigact) { /* No.. Then we need to allocate one for the new action. */ sigact = sig_allocateaction(); /* An error has occurred if we could not allocate the sigaction */ if (!sigact) { set_errno(ENOMEM); return ERROR; } /* Put the signal number in the queue entry */ sigact->signo = (uint8_t)signo; /* Add the new sigaction to sigactionq */ sq_addlast((FAR sq_entry_t*)sigact, &rtcb->sigactionq); } /* Set the new sigaction */ COPY_SIGACTION(&sigact->act, act); } return OK; }
static inline void group_release(FAR struct task_group_s *group) { /* Free all un-reaped child exit status */ #if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS) group_removechildren(group); #endif #ifndef CONFIG_DISABLE_SIGNALS /* Release pending signals */ sig_release(group); #endif #ifndef CONFIG_DISABLE_PTHREAD /* Release pthread resources */ pthread_release(group); #endif #if CONFIG_NFILE_DESCRIPTORS > 0 /* Free all file-related resources now. We really need to close files as * soon as possible while we still have a functioning task. */ /* Free resources held by the file descriptor list */ files_releaselist(&group->tg_filelist); #if CONFIG_NFILE_STREAMS > 0 /* Free resource held by the stream list */ lib_stream_release(group); #endif /* CONFIG_NFILE_STREAMS */ #endif /* CONFIG_NFILE_DESCRIPTORS */ #if CONFIG_NSOCKET_DESCRIPTORS > 0 /* Free resource held by the socket list */ net_releaselist(&group->tg_socketlist); #endif /* CONFIG_NSOCKET_DESCRIPTORS */ #ifndef CONFIG_DISABLE_ENVIRON /* Release all shared environment variables */ env_release(group); #endif #ifndef CONFIG_DISABLE_MQUEUE /* Close message queues opened by members of the group */ mq_release(group); #endif #if defined(CONFIG_BUILD_KERNEL) && defined(CONFIG_MM_SHM) /* Release any resource held by shared memory virtual page allocator */ (void)shm_group_release(group); #endif #ifdef CONFIG_ARCH_ADDRENV /* Destroy the group address environment */ (void)up_addrenv_destroy(&group->tg_addrenv); /* Mark no address environment */ g_gid_current = 0; #endif #if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV) /* Remove the group from the list of groups */ group_remove(group); #endif #ifdef HAVE_GROUP_MEMBERS /* Release the members array */ if (group->tg_members) { sched_kfree(group->tg_members); group->tg_members = NULL; } #endif #if CONFIG_NFILE_STREAMS > 0 && defined(CONFIG_MM_KERNEL_HEAP) /* In a flat, single-heap build. The stream list is part of the * group structure and, hence will be freed when the group structure * is freed. Otherwise, it is separately allocated an must be * freed here. */ # if defined(CONFIG_BUILD_PROTECTED) /* In the protected build, the task's stream list is always allocated * and freed from the single, global user allocator. */ sched_ufree(group->tg_streamlist); # elif defined(CONFIG_BUILD_KERNEL) /* In the kernel build, the unprivileged process' stream list will be * allocated from with its per-process, private user heap. But in that * case, there is no reason to do anything here: That allocation resides * in the user heap which which be completely freed when we destroy the * process' address environment. */ if ((group->tg_flags & GROUP_FLAG_PRIVILEGED) != 0) { /* But kernel threads are different in this build configuration: Their * stream lists were allocated from the common, global kernel heap and * must explicitly freed here. */ sched_kfree(group->tg_streamlist); } # endif #endif #if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT) /* If there are threads waiting for this group to be freed, then we cannot * yet free the memory resources. Instead just mark the group deleted * and wait for those threads complete their waits. */ if (group->tg_nwaiters > 0) { group->tg_flags |= GROUP_FLAG_DELETED; } else #endif { /* Release the group container itself */ sched_kfree(group); } }