From: Michalis Pappas Date: Sun, 7 Jan 2024 15:50:12 +0000 (+0100) Subject: lib/posix-process/signal: Add signal descriptors and primitives X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=2437ed7135fe094ea2e131db7f0a4fbf6fc3b1d9;p=unikraft%2Funikraft.git lib/posix-process/signal: Add signal descriptors and primitives Introduce signal descriptors into `struct posix_process` and `struct posix_thread`. Introduce primitives for various signal operations such as initialization, allocation, and queueing. Initialize signal descriptors upon creating a new process or a thread. Checkpatch-Ignore: LONG_LINE Checkpatch-Ignore: MACRO_ARG_REUSE Checkpatch-Ignore: SPACING Signed-off-by: Michalis Pappas Reviewed-by: Ioan-Teodor Teugea Reviewed-by: Sergiu Moga Reviewed-by: Andrei Tatar Approved-by: Andrei Tatar GitHub-Closes: #1248 --- diff --git a/lib/posix-process/Config.uk b/lib/posix-process/Config.uk index a4cd42fbb..1338177f8 100644 --- a/lib/posix-process/Config.uk +++ b/lib/posix-process/Config.uk @@ -24,6 +24,7 @@ config LIBPOSIX_PROCESS_SIGNAL bool "POSIX signals (EXPERIMENTAL)" select LIBPOSIX_PROCESS_PIDS select LIBSYSCALL_SHIM + select LIBUKLOCK config LIBPOSIX_PROCESS_CLONE bool "clone() system call" diff --git a/lib/posix-process/Makefile.uk b/lib/posix-process/Makefile.uk index 30821a1c8..a36759ca2 100644 --- a/lib/posix-process/Makefile.uk +++ b/lib/posix-process/Makefile.uk @@ -18,6 +18,9 @@ LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/deprecated.c LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/process.c LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/wait.c LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signals.c + +LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_SIGNAL) += $(LIBPOSIX_PROCESS_BASE)/signal/signal.c + LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/clone.c LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/clonetab.ld LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/arch/$(CONFIG_UK_ARCH)/clone.c|$(CONFIG_UK_ARCH) diff --git a/lib/posix-process/process.c b/lib/posix-process/process.c index 12a19c33c..fec17e2c5 100644 --- a/lib/posix-process/process.c +++ b/lib/posix-process/process.c @@ -54,6 +54,10 @@ #include #endif /* CONFIG_LIBPOSIX_PROCESS_CLONE */ +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL +#include "signal/signal.h" +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ + #include "process.h" /** @@ -147,11 +151,35 @@ static struct posix_thread *pprocess_create_pthread( pthread->process = pprocess; pthread->tid = tid; pthread->thread = th; - uk_list_add_tail(&pthread->thread_list_entry, &pprocess->threads); + +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + err = pprocess_signal_tdesc_alloc(pthread); + if (unlikely(err)) { + uk_pr_err("Could not allocate signal descriptor\n"); + /* Handle rollback manually to avoid adding more + * signal conditionals. + */ + uk_free(a, pthread); + goto err_free_tid; + } + err = pprocess_signal_tdesc_init(pthread); + if (unlikely(err)) { + uk_pr_err("Could not initialize signal descriptor\n"); + /* Handle rollback manually to avoid adding more + * signal conditionals. + */ + pprocess_signal_tdesc_free(pthread); + uk_free(a, pthread); + goto err_free_tid; + } +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ /* Store reference to pthread with TID */ tid_thread[tid] = pthread; + /* Add to parent's list of threads */ + uk_list_add_tail(&pthread->thread_list_entry, &pprocess->threads); + uk_pr_debug("Process PID %d: New thread TID %d\n", (int) pprocess->pid, (int) pthread->tid); return pthread; @@ -171,6 +199,10 @@ static void pprocess_release_pthread(struct posix_thread *pthread) UK_ASSERT(pthread); UK_ASSERT(pthread->_a); +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + pprocess_signal_tdesc_free(pthread); +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ + /* remove from process' thread list */ uk_list_del_init(&pthread->thread_list_entry); @@ -223,6 +255,23 @@ int uk_posix_process_create(struct uk_alloc *a, UK_INIT_LIST_HEAD(&pprocess->threads); UK_INIT_LIST_HEAD(&pprocess->children); +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + ret = pprocess_signal_pdesc_alloc(pprocess); + if (unlikely(ret)) { + uk_pr_err("Could not allocate signal descriptor\n"); + /* Free manually as we can jump to err_free_pprocess + * after this allocation is successful. + */ + uk_free(a, pprocess); + goto err_out; + } + ret = pprocess_signal_pdesc_init(pprocess); + if (unlikely(ret)) { + uk_pr_err("Could not initialize signal descriptor\n"); + goto err_free_pprocess; + } +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ + /* Check if we have a pthread structure already for this thread * or if we need to allocate one */ @@ -249,12 +298,21 @@ int uk_posix_process_create(struct uk_alloc *a, uk_list_add_tail(&(*pthread)->thread_list_entry, &pprocess->threads); +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + /* Reset signal state of this thread */ + ret = pprocess_signal_tdesc_init(*pthread); + if (unlikely(ret)) { + uk_pr_err("Could not initialize signal descriptor\n"); + goto err_free_pprocess; + } +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ + /* Release original process if it became empty of threads */ if (uk_list_empty(&orig_pprocess->threads)) pprocess_release(orig_pprocess); } - /* Add to process table */ + /* Add to process table. No failure past this point. */ if (unlikely((unsigned long)pprocess->pid >= ARRAY_SIZE(pid_process))) { uk_pr_err("Process limit reached, could not create new process\n"); ret = -EAGAIN; @@ -276,6 +334,9 @@ int uk_posix_process_create(struct uk_alloc *a, return 0; err_free_pprocess: +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + pprocess_signal_pdesc_free(pprocess); +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ uk_free(a, pprocess); err_out: return ret; @@ -311,6 +372,10 @@ static void pprocess_release(struct posix_process *pprocess) } } +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + pprocess_signal_pdesc_free(pprocess); +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ + pid_process[pprocess->pid] = NULL; uk_pr_debug("Process PID %d released\n", diff --git a/lib/posix-process/process.h b/lib/posix-process/process.h index 44c2c07f8..843dd779e 100644 --- a/lib/posix-process/process.h +++ b/lib/posix-process/process.h @@ -71,6 +71,9 @@ struct posix_process { struct uk_list_head child_list_entry; struct uk_list_head threads; struct uk_alloc *_a; +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + struct uk_signal_pdesc *signal; +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ /* TODO: Mutex */ }; @@ -83,6 +86,9 @@ struct posix_thread { struct uk_thread *thread; struct uk_alloc *_a; enum posix_thread_state state; +#if CONFIG_LIBPOSIX_PROCESS_SIGNAL + struct uk_signal_tdesc *signal; +#endif /* CONFIG_LIBPOSIX_PROCESS_SIGNAL */ /* TODO: Mutex */ }; diff --git a/lib/posix-process/signal/process.h b/lib/posix-process/signal/process.h new file mode 100644 index 000000000..d8d38b080 --- /dev/null +++ b/lib/posix-process/signal/process.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ + +#include "../process.h" diff --git a/lib/posix-process/signal/signal.c b/lib/posix-process/signal/signal.c new file mode 100644 index 000000000..20b6ccaa3 --- /dev/null +++ b/lib/posix-process/signal/signal.c @@ -0,0 +1,276 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ + +#include +#include +#include + +#include "process.h" +#include "sigset.h" +#include "signal.h" + +/* Enqueue signal for a thread or a process + * + * Setting pthread to NULL signifies that the signal + * targets the process. + */ +static int pprocess_signal_enqueue(struct posix_process *pproc, + struct posix_thread *pthread, + struct uk_signal *sig) +{ + int signum; + + UK_ASSERT(sig); + UK_ASSERT(pproc); + + if (pthread) + UK_ASSERT(pthread->process == pproc); + + if (unlikely(pproc->signal->queued_count >= pproc->signal->queued_max)) + return -EAGAIN; + + signum = sig->siginfo.si_signo; + + if (pthread) { + /* Standard signals can be queued once */ + if (signum < SIGRTMIN && IS_PENDING(pthread->signal->sigqueue, signum)) + return 0; + + uk_pr_debug("Queueing signal %d for tid %d (pid %d)\n", + signum, pthread->tid, pproc->pid); + + uk_list_add_tail(&sig->list_head, + &pthread->signal->sigqueue.list_head[signum]); + SET_PENDING(pproc->signal->sigqueue, signum); + } else { + /* Standard signals can be queued once */ + if (signum < SIGRTMIN && IS_PENDING(pproc->signal->sigqueue, signum)) + return 0; + + uk_pr_debug("Queueing signal %d for pid %d\n", + signum, pproc->pid); + + uk_list_add_tail(&sig->list_head, + &pproc->signal->sigqueue.list_head[signum]); + SET_PENDING(pproc->signal->sigqueue, signum); + } + + pproc->signal->queued_count++; + + return 0; +} + +struct uk_signal *pprocess_signal_dequeue(struct posix_process *pproc, + struct posix_thread *pthread, + int signum) +{ + struct uk_signal_queue *sigqueue; + struct uk_signal *sig; + + UK_ASSERT(pproc); + + if (pthread) { + UK_ASSERT(pthread->process == pproc); + sigqueue = &pthread->signal->sigqueue; + } else { + sigqueue = &pproc->signal->sigqueue; + } + + sig = uk_list_first_entry_or_null(&sigqueue->list_head[signum], + struct uk_signal, + list_head); + if (!sig) + return sig; + + uk_list_del(&sig->list_head); + + /* Reset pending bit if the signal queue is empty */ + if (uk_list_empty(&sigqueue->list_head[signum])) { + if (pthread) + RESET_PENDING(pthread->signal->sigqueue, signum); + else + RESET_PENDING(pproc->signal->sigqueue, signum); + } + + pproc->signal->queued_count--; + + return sig; +} + +struct uk_signal *pprocess_signal_next_pending_t(struct posix_thread *pthread) +{ + struct posix_process *pproc; + struct uk_signal *sig; + int signum; + + pproc = tid2pprocess(pthread->tid); + UK_ASSERT(pproc); + + pprocess_signal_foreach(signum) { + if (!pprocess_signal_is_deliverable(pthread, signum)) + continue; + + sig = pprocess_signal_dequeue(pproc, pthread, signum); + if (sig) + return sig; + } + + return NULL; +} + +void pprocess_signal_clear_pending(struct posix_process *proc, int signum) +{ + struct posix_thread *thread, *threadn; + struct uk_signal *sig; + + if (IS_PENDING(proc->signal->sigqueue, signum)) { + while ((sig = pprocess_signal_dequeue(proc, NULL, signum))) + uk_signal_free(proc->_a, sig); + } + + uk_pprocess_foreach_pthread(proc, thread, threadn) { + if (!IS_PENDING(thread->signal->sigqueue, signum)) + continue; + while ((sig = pprocess_signal_dequeue(proc, thread, signum))) + uk_signal_free(thread->_a, sig); + } +} + +void pprocess_signal_sigaction_clear(struct kern_sigaction *ks) +{ + ks->ks_handler = SIG_DFL; + ks->ks_flags = 0; + ks->ks_restorer = NULL; + uk_sigemptyset(&ks->ks_mask); +} + +int pprocess_signal_sigaction_new(struct uk_alloc *alloc, struct uk_signal_pdesc *pd) +{ + pd->sigaction = uk_malloc(alloc, sizeof(struct uk_sigaction)); + if (unlikely(!pd->sigaction)) { + uk_pr_err("Could not allocate memory\n"); + return -ENOMEM; + } + + pd->sigaction->alloc = alloc; + uk_refcount_init(&pd->sigaction->refcnt, 1); + + return 0; +} + +int pprocess_signal_pdesc_alloc(struct posix_process *process) +{ + UK_ASSERT(process); + + process->signal = uk_malloc(process->_a, + sizeof(struct uk_signal_pdesc)); + if (unlikely(!process->signal)) { + uk_pr_err("Could not allocate memory\n"); + return -ENOMEM; + } + + return 0; +} + +int pprocess_signal_tdesc_alloc(struct posix_thread *thread) +{ + UK_ASSERT(thread); + + thread->signal = uk_malloc(thread->_a, sizeof(struct uk_signal_tdesc)); + if (unlikely(!thread->signal)) { + uk_pr_err("Could not allocate memory\n"); + return -ENOMEM; + } + + return 0; +} + +int pprocess_signal_pdesc_init(struct posix_process *process) +{ + struct uk_signal_pdesc *pd; + int signum; + int rc; + + UK_ASSERT(process); + UK_ASSERT(process->signal); + + pd = process->signal; + + pd->queued_count = 0; + pd->queued_max = _POSIX_SIGQUEUE_MAX; + + uk_sigemptyset(&pd->sigqueue.pending); + + pprocess_signal_foreach(signum) + UK_INIT_LIST_HEAD(&pd->sigqueue.list_head[signum]); + + rc = pprocess_signal_sigaction_new(process->_a, pd); + if (unlikely(rc)) + return rc; + + pprocess_signal_foreach(signum) + pprocess_signal_sigaction_clear(KERN_SIGACTION(process, signum)); + + return 0; +} + +int pprocess_signal_tdesc_init(struct posix_thread *thread) +{ + struct uk_signal_tdesc *td; + int signum; + + UK_ASSERT(thread); + UK_ASSERT(thread->signal); + + td = thread->signal; + + uk_sigemptyset(&td->mask); + uk_sigemptyset(&td->sigqueue.pending); + + pprocess_signal_foreach(signum) + UK_INIT_LIST_HEAD(&td->sigqueue.list_head[signum]); + + uk_semaphore_init(&thread->signal->pending_semaphore, 0); + uk_semaphore_init(&thread->signal->deliver_semaphore, 0); + + return 0; +} + +void pprocess_signal_pdesc_free(struct posix_process *process) +{ + struct uk_signal *sig; + int signum; + + UK_ASSERT(process); + UK_ASSERT(process->signal); + + pprocess_signal_foreach(signum) + while ((sig = pprocess_signal_dequeue(process, NULL, signum))) + uk_signal_free(process->_a, sig); + + pprocess_signal_sigaction_release(process->signal->sigaction); + + uk_free(process->_a, process->signal); +} + +void pprocess_signal_tdesc_free(struct posix_thread *thread) +{ + struct posix_process *pproc; + struct uk_signal *sig; + int signum; + + UK_ASSERT(thread); + UK_ASSERT(thread->signal); + + pproc = tid2pprocess(thread->tid); + UK_ASSERT(pproc); + + pprocess_signal_foreach(signum) + while ((sig = pprocess_signal_dequeue(pproc, thread, signum))) + uk_signal_free(thread->_a, sig); + + uk_signal_free(thread->process->_a, thread->signal); +} diff --git a/lib/posix-process/signal/signal.h b/lib/posix-process/signal/signal.h new file mode 100644 index 000000000..d91ceba21 --- /dev/null +++ b/lib/posix-process/signal/signal.h @@ -0,0 +1,255 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ + +#ifndef __UK_PROCESS_SIGNAL_H__ +#define __UK_PROCESS_SIGNAL_H__ + +#include +#include + +#include +#include +#include +#include +#include + +#include "process.h" +#include "sigset.h" + +#define SIG_ARRAY_COUNT _NSIG /* SIGRTMAX + 1 */ + +/* Check if signal number is valid */ +#define IS_VALID(_signum) \ + ((_signum) > 0 && (_signum) <= SIGRTMAX) + +/* Check whether signal number is pending in sigqueue */ +#define IS_PENDING(_sigqueue, _signum) \ + uk_sigismember(&(_sigqueue).pending, (_signum)) + +/* Set signal number in sigqueue */ +#define SET_PENDING(_sigqueue, _signum) \ + uk_sigaddset(&(_sigqueue).pending, (_signum)) + +/* Clear a signal from a sigqueue */ +#define RESET_PENDING(_sigqueue, _signum) \ + uk_sigdelset(&(_sigqueue).pending, (_signum)) + +/* Check if posix thread masks signal number */ +#define IS_MASKED(_t, _signum) \ + uk_sigismember(&(_t)->signal->mask, (_signum)) + +/* Sets a posix thread's mask of the given signal number */ +#define SET_MASKED(_t, _signum) \ + uk_sigaddset(&(_t)->signal->mask, (_signum)) + +/* Check if signal is ignored by a process. A signal is ignored if it + * is explicitly set to IGNORE by sigaction, or if it is set to its + * default action and that action is IGNORE. + */ +#define IS_IGNORED(_pproc, _signum) \ + ((KERN_SIGACTION(_pproc, _signum)->ks_handler == SIG_IGN) || \ + (KERN_SIGACTION(_pproc, _signum)->ks_handler == SIG_DFL && \ + UK_BIT(_signum) & SIGACT_IGN_MASK)) + +/* Allocate and return `struct uk_signal` or NULL */ +#define uk_signal_alloc(_alloc) \ + uk_zalloc(_alloc, sizeof(struct uk_signal)) + +/* Free a previously allocated `struct uk_signal` */ +#define uk_signal_free(_alloc, _sig) \ + uk_free(_alloc, _sig) + +/* Helper to get pointer to kern_sigaction from process, + * for a given signal + */ +#define KERN_SIGACTION(_proc, _signum) \ + ({ \ + UK_ASSERT((_proc)->signal); \ + UK_ASSERT((_proc)->signal->sigaction); \ + &(_proc)->signal->sigaction->ks[_signum]; \ + }) + +/* Helper to iterate over all signals (std + rt) */ +#define pprocess_signal_foreach(_sn) \ + for ((_sn) = 1; (__sz)(_sn) < SIG_ARRAY_COUNT; (_sn)++) + +/* Helper to iterate over standard signals */ +#define pprocess_stdsig_foreach(_sn) \ + for ((_sn) = 1; (__sz)(_sn) < SIGRTMIN; (_sn)++) + +/* Kernel version of `struct sigaction` passed to rt_sigaction(). The order + * of the elements of this struct is different of the `struct sigaction` + * passed to the sigaction() glibc wrapper. + */ +struct kern_sigaction { + void (*ks_handler)(int signo); + unsigned long ks_flags; + void (*ks_restorer)(void); + uk_sigset_t ks_mask; +}; + +struct uk_sigaction { + struct kern_sigaction ks[SIG_ARRAY_COUNT]; + struct uk_alloc *alloc; + __atomic refcnt; +}; + +#if CONFIG_LIBPOSIX_PROCESS_PIDS + +/* Descriptor of a pending signal. + * + * Each pending signal is described as a set of + * information `siginfo`. This includes the signal + * number, sending pid, address of faulting + * instruction, and more. The individual fields of + * `siginfo_t` are described in `man siginfo_t`. + */ +struct uk_signal { + siginfo_t siginfo; + struct uk_list_head list_head; +}; + +/* Descriptor of a signal queue. + * + * Pending signals are expressed in a signal set, that + * provides information on which signal numbers are pending. + * + * By POSIX, standard signals are queued once regardless of + * the number of times the signal was issued by the sender. + * Real-time signals allow in-order delivery of multiple + * instances of a given signal. + * + * This structure maintains an list of `struct uk_signal` for + * each signal number. Lists of standard signals can only + * contain a single item. + */ +struct uk_signal_queue { + uk_sigset_t pending; + struct uk_list_head list_head[SIG_ARRAY_COUNT]; +}; + +/* Signal descriptor of a posix_process. + * + * A process may queue up to `queued_max` signals, + * the value of which is set at init time. + * POSIX requires at least _POSIX_SIGQUEUE_MAX + * signals, while Linux allows the user to configure + * that value via rlimit. + * + * Signals can be targeting the process, or individual + * threads. Signals pending for the process are queued + * in `sigqueue`. Signals pending for individual + * threads are queued in thread-specific queues (see + * `struct uk_signal_tdesc`). + * + * Each signal defines a signal action, which may + * be the default one or a custom one specified by + * calling `rt_sigaction`. Signal actions are defined + * at the process level, i.e. are common for all + * threads of a given process. + */ +struct uk_signal_pdesc { + __sz queued_count; + __sz queued_max; + struct uk_signal_queue sigqueue; + /* We use dynamically allocated memory for sigaction as passing + * CLONE_SIGHAND to clone() requires that the parent and the child + * share the same set of handlers. + */ + struct uk_sigaction *sigaction; +}; + +/* Signal descriptor of a posix_thread. + * + * Each thread maintains its own signal mask. + * That mask applies to signals targeting + * that thread, and also impacts the delivery + * of process-wide signals, as these are + * delivered to the first thread that does + * not mask that signal. + * + * Each thread also maintains its own signal + * queue, as besides signals targeting the + * process, signals can target individual + * threads. For details on signal queues see + * the description of `struct uk_signal_queue`. + */ +struct uk_signal_tdesc { + uk_sigset_t mask; + uk_sigset_t sigwait_set; + struct uk_signal_queue sigqueue; + struct uk_semaphore deliver_semaphore; + struct uk_semaphore pending_semaphore; +}; + +/* Allocate signal descriptor of a posix process */ +int pprocess_signal_pdesc_alloc(struct posix_process *proc); + +/* Allocate signal descriptor of a posix thread */ +int pprocess_signal_tdesc_alloc(struct posix_thread *thread); + +/* Initialize signal descriptors of a posix process */ +int pprocess_signal_pdesc_init(struct posix_process *proc); + +/* Initialize signal descriptors of a posix thread */ +int pprocess_signal_tdesc_init(struct posix_thread *thread); + +/* Free signal descritors of a posix process + * + * This function is safe to call at thread termination as + * we reject signals once the process exits. + */ +void pprocess_signal_pdesc_free(struct posix_process *process); + +/* Free signal descritors of a posix thread + * + * This function is safe to call at thread termination as + * we reject signals once the process exits. + */ +void pprocess_signal_tdesc_free(struct posix_thread *thread); + +/* Dequeue a signal from a thread or process + * + * Setting pthread to NULL signifies that the signal + * is queued at the process + */ +struct uk_signal *pprocess_signal_dequeue(struct posix_process *pproc, + struct posix_thread *pthread, + int signum); + +/* Allocates and, upon success, acquires a new instance of uk_sigaction. + * Does not clear or otherwise initialize signal dispositions. + */ +int pprocess_signal_sigaction_new(struct uk_alloc *alloc, + struct uk_signal_pdesc *pd); + +static inline void pprocess_signal_sigaction_acquire(struct uk_sigaction *sa) +{ + uk_refcount_acquire(&sa->refcnt); +} + +static inline void pprocess_signal_sigaction_release(struct uk_sigaction *sa) +{ + if (uk_refcount_release(&sa->refcnt)) + uk_free(sa->alloc, sa); +} + +/* Clears the fields of an instance of struct uk_sigaction */ +void pprocess_signal_sigaction_clear(struct kern_sigaction *ks); + +/* Clear pending signal(s) from process. If the signum corresponds to + * an std-signal, it clears that an signal from pending. Otherwise, + * if signum corresponding an rt-signal it clears all instances from + * the queue. + */ +void pprocess_signal_clear_pending(struct posix_process *proc, int signum); + +/* Get next pending signal of a given thread */ +struct uk_signal *pprocess_signal_next_pending_t(struct posix_thread *pthread); + +#endif /* CONFIG_LIBPOSIX_PROCESS_PIDS */ + +#endif /* __UK_PROCESS_SIGNAL_H__ */