summaryrefslogtreecommitdiff
path: root/components/lwp/syscall/syscall_signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/lwp/syscall/syscall_signal.c')
-rw-r--r--components/lwp/syscall/syscall_signal.c614
1 files changed, 614 insertions, 0 deletions
diff --git a/components/lwp/syscall/syscall_signal.c b/components/lwp/syscall/syscall_signal.c
new file mode 100644
index 0000000000..e0fb7459c1
--- /dev/null
+++ b/components/lwp/syscall/syscall_signal.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "syscall_internal.h"
+
+struct k_sigaction
+{
+ void (*handler)(int);
+ unsigned long flags;
+ void (*restorer)(void);
+ unsigned mask[2];
+};
+
+/**
+ * @brief Changes the action taken by the system on receiving a signal.
+ *
+ * This system call allows a process to specify how signals should be handled. It allows you to set a
+ * new action for a specific signal, retrieve the old action, and define the signal mask that should
+ * be applied during the execution of the signal handler.
+ *
+ * @param[in] sig The signal number for which the action is to be set or retrieved.
+ * Signal numbers are typically defined as constants (e.g., `SIGINT`, `SIGTERM`).
+ * @param[in] act A pointer to a `k_sigaction` structure that specifies the new action for the signal.
+ * If `act` is `NULL`, the signal's action is not changed.
+ * @param[out] oact A pointer to a `k_sigaction` structure where the old action will be stored.
+ * If `oact` is `NULL`, the old action is not retrieved.
+ * @param[in] sigsetsize The size of the `sigset_t` structure used in `k_sigaction`. This is to ensure the
+ * compatibility with the signal mask size.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note The `k_sigaction` structure allows you to specify the signal handler, signal mask, and flags for
+ * the signal action. It is important to correctly configure the handler to prevent unexpected
+ * behavior in the signal handling process.
+ *
+ * @warning Be cautious when modifying signal handling behavior, as incorrect configuration may result
+ * in unhandled signals or undefined behavior. Signal handlers should be designed to perform
+ * minimal, safe operations.
+ *
+ * @see sys_signal(), sys_sigprocmask()
+ */
+sysret_t sys_sigaction(int sig, const struct k_sigaction *act,
+ struct k_sigaction *oact, size_t sigsetsize)
+{
+ int ret = -RT_EINVAL;
+ struct rt_lwp *lwp;
+ struct lwp_sigaction kact, *pkact = RT_NULL;
+ struct lwp_sigaction koact, *pkoact = RT_NULL;
+
+ if (!sigsetsize)
+ {
+ SET_ERRNO(EINVAL);
+ goto out;
+ }
+ if (sigsetsize > sizeof(lwp_sigset_t))
+ {
+ sigsetsize = sizeof(lwp_sigset_t);
+ }
+ if (!act && !oact)
+ {
+ SET_ERRNO(EINVAL);
+ goto out;
+ }
+ if (oact)
+ {
+ if (!lwp_user_accessable((void *)oact, sizeof(*oact)))
+ {
+ SET_ERRNO(EFAULT);
+ goto out;
+ }
+ pkoact = &koact;
+ }
+ if (act)
+ {
+ if (!lwp_user_accessable((void *)act, sizeof(*act)))
+ {
+ SET_ERRNO(EFAULT);
+ goto out;
+ }
+ kact.sa_flags = act->flags;
+ kact.__sa_handler._sa_handler = act->handler;
+ lwp_memcpy(&kact.sa_mask, &act->mask, sigsetsize);
+ kact.sa_restorer = act->restorer;
+ pkact = &kact;
+ }
+
+ lwp = lwp_self();
+ RT_ASSERT(lwp);
+ ret = lwp_signal_action(lwp, sig, pkact, pkoact);
+#ifdef ARCH_MM_MMU
+ if (ret == 0 && oact)
+ {
+ lwp_put_to_user(&oact->handler, &pkoact->__sa_handler._sa_handler, sizeof(void (*)(int)));
+ lwp_put_to_user(&oact->mask, &pkoact->sa_mask, sigsetsize);
+ lwp_put_to_user(&oact->flags, &pkoact->sa_flags, sizeof(int));
+ lwp_put_to_user(&oact->restorer, &pkoact->sa_restorer, sizeof(void (*)(void)));
+ }
+#endif /* ARCH_MM_MMU */
+out:
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+static int mask_command_u2k[] = {
+ [SIG_BLOCK] = LWP_SIG_MASK_CMD_BLOCK,
+ [SIG_UNBLOCK] = LWP_SIG_MASK_CMD_UNBLOCK,
+ [SIG_SETMASK] = LWP_SIG_MASK_CMD_SET_MASK,
+};
+
+/**
+ * @brief Sets or retrieves the signal mask for the calling process.
+ *
+ * This system call allows the caller to block or unblock signals by modifying the signal mask. The signal
+ * mask determines which signals are blocked and which signals can be delivered to the process. The
+ * function can also be used to retrieve the current signal mask.
+ *
+ * @param[in] how The action to be taken on the signal mask. It can be one of the following values:
+ * - `SIG_BLOCK`: Add the signals in `sigset` to the current mask.
+ * - `SIG_UNBLOCK`: Remove the signals in `sigset` from the current mask.
+ * - `SIG_SETMASK`: Set the signal mask to the value in `sigset`, replacing the current mask.
+ * @param[in] sigset A pointer to a `sigset_t` structure that specifies the signals to be blocked or unblocked.
+ * This parameter is ignored when `how` is `SIG_SETMASK`, in which case `sigset` is used
+ * as the new signal mask.
+ * @param[out] oset A pointer to a `sigset_t` structure where the previous signal mask will be stored.
+ * If `oset` is `NULL`, the previous signal mask will not be returned.
+ * @param[in] size The size of the `sigset_t` structure, ensuring compatibility with the signal mask.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note Modifying the signal mask prevents signals from being delivered to the process while they are blocked.
+ * Once the signals are unblocked, they will be delivered to the process if they are pending.
+ *
+ * @warning Be careful when blocking signals, especially critical ones like `SIGKILL`, as it may interfere
+ * with the normal operation of the system. Ensure that signal masks are managed carefully to avoid
+ * missing important signals.
+ *
+ * @see sys_sigaction(), sys_sigpending()
+ */
+sysret_t sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t size)
+{
+ int ret = -1;
+ lwp_sigset_t *pnewset = RT_NULL, *poldset = RT_NULL;
+#ifdef ARCH_MM_MMU
+ lwp_sigset_t newset, oldset;
+#endif /* ARCH_MM_MMU*/
+
+ if (!size)
+ {
+ return -EINVAL;
+ }
+ if (!oset && !sigset)
+ {
+ return -EINVAL;
+ }
+ if (size > sizeof(lwp_sigset_t))
+ {
+ size = sizeof(lwp_sigset_t);
+ }
+ if (oset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = &oldset;
+#else
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = (lwp_sigset_t *)oset;
+#endif
+ }
+ if (sigset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&newset, (void *)sigset, size);
+ pnewset = &newset;
+#else
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ pnewset = (lwp_sigset_t *)sigset;
+#endif /* ARCH_MM_MMU */
+ }
+ ret = lwp_thread_signal_mask(rt_thread_self(), mask_command_u2k[how], pnewset, poldset);
+#ifdef ARCH_MM_MMU
+ if (ret < 0)
+ {
+ return ret;
+ }
+ if (oset)
+ {
+ lwp_put_to_user(oset, poldset, size);
+ }
+#endif /* ARCH_MM_MMU */
+ return (ret < 0 ? -EFAULT : ret);
+}
+
+/**
+ * @brief Retrieves the set of signals that are pending for delivery to the calling process.
+ *
+ * This system call allows a process to query the set of signals that are pending, i.e., signals that have
+ * been sent to the process but have not yet been delivered because the process is blocking those signals
+ * or has not yet handled them. The function returns the set of signals that are waiting to be delivered.
+ *
+ * @param[out] sigset A pointer to a `sigset_t` structure where the set of pending signals will be stored.
+ * The `sigset_t` structure will contain the signals that are pending for delivery.
+ * @param[in] sigsize The size of the `sigset_t` structure, used to ensure compatibility with the signal set.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note The returned signal set will contain the signals that have been sent to the process but are blocked,
+ * or that are waiting to be handled. These signals will be delivered once they are unblocked or the
+ * process handles them.
+ *
+ * @warning Be cautious when querying pending signals, as unblocking too many signals at once may lead
+ * to unexpected behavior or a flood of signal deliveries. It's recommended to carefully manage
+ * the signals the process can accept at any given time.
+ *
+ * @see sys_sigaction(), sys_sigprocmask()
+ */
+sysret_t sys_sigpending(sigset_t *sigset, size_t sigsize)
+{
+ sysret_t ret = 0;
+ lwp_sigset_t lwpset;
+
+ /* Verify and Get sigset, timeout */
+ if (!sigset || !lwp_user_accessable((void *)sigset, sigsize))
+ {
+ ret = -EFAULT;
+ }
+ else
+ {
+ /* Fit sigset size to lwp set */
+ if (sizeof(lwpset) < sigsize)
+ {
+ LOG_I("%s: sigsize (%lx) extends lwp sigset chunk\n", __func__, sigsize);
+ sigsize = sizeof(lwpset);
+ }
+
+ lwp_thread_signal_pending(rt_thread_self(), &lwpset);
+
+ if (!lwp_put_to_user(sigset, &lwpset, sigsize))
+ {
+ RT_ASSERT(0); /* should never happened */
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Waits for a signal to be delivered, with a timeout.
+ *
+ * This system call allows a process to wait for one of the signals specified in the `sigset` to be delivered.
+ * The process will block until a signal in the set is received or the specified timeout period expires.
+ * If the signal is received before the timeout, information about the signal will be returned in the `siginfo_t` structure.
+ * If the timeout expires without any signal being delivered, the function will return with an appropriate error code.
+ *
+ * @param[in] sigset A pointer to a `sigset_t` structure that specifies the set of signals to wait for.
+ * The function will block until a signal in this set is received, or the timeout expires.
+ * @param[out] info A pointer to a `siginfo_t` structure where information about the delivered signal will be stored.
+ * If no signal is received before the timeout, this structure will not be filled.
+ * @param[in] timeout A pointer to a `timespec` structure that specifies the maximum amount of time to wait
+ * for a signal to be delivered. If this value is `NULL`, the function will wait indefinitely.
+ * @param[in] sigsize The size of the `sigset_t` structure, ensuring compatibility with the signal set.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note If the `timeout` is `NULL`, the function will block indefinitely until a signal is delivered.
+ * If a signal is received, the corresponding information is returned in the `siginfo_t` structure.
+ * The `sigset` should contain only the signals you are interested in.
+ *
+ * @warning If the timeout expires, no signal will be delivered, and the function will return a timeout error.
+ * Make sure to handle the timeout case correctly to prevent any unexpected behavior.
+ *
+ * @see sys_sigaction(), sys_sigtimedwait()
+ */
+sysret_t sys_sigtimedwait(const sigset_t *sigset, siginfo_t *info, const struct timespec *timeout, size_t sigsize)
+{
+ int sig;
+ size_t ret;
+ lwp_sigset_t lwpset;
+ siginfo_t kinfo;
+ struct timespec ktimeout;
+ struct timespec *ptimeout;
+
+ /* for RT_ASSERT */
+ RT_UNUSED(ret);
+
+ /* Fit sigset size to lwp set */
+ if (sizeof(lwpset) < sigsize)
+ {
+ LOG_I("%s: sigsize (%lx) extends lwp sigset chunk\n", __func__, sigsize);
+ sigsize = sizeof(lwpset);
+ }
+ else
+ {
+ /* if sigset of user is smaller, clear extra space */
+ memset(&lwpset, 0, sizeof(lwpset));
+ }
+
+ /* Verify and Get sigset, timeout */
+ if (!sigset || !lwp_user_accessable((void *)sigset, sigsize))
+ {
+ return -EFAULT;
+ }
+ else
+ {
+ ret = lwp_get_from_user(&lwpset, (void *)sigset, sigsize);
+ RT_ASSERT(ret == sigsize);
+ }
+
+ if (timeout)
+ {
+ if (!lwp_user_accessable((void *)timeout, sizeof(*timeout)))
+ {
+ return -EFAULT;
+ }
+ else
+ {
+ ret = lwp_get_from_user(&ktimeout, (void *)timeout, sizeof(*timeout));
+ ptimeout = &ktimeout;
+ RT_ASSERT(ret == sizeof(*timeout));
+ }
+ }
+ else
+ {
+ ptimeout = RT_NULL;
+ }
+
+ sig = lwp_thread_signal_timedwait(rt_thread_self(), &lwpset, &kinfo, ptimeout);
+
+ if (sig > 0 && info)
+ {
+ if (!lwp_user_accessable((void *)info, sizeof(*info)))
+ {
+ return -EFAULT;
+ }
+ else
+ {
+ ret = lwp_put_to_user(info, &kinfo, sizeof(*info));
+ RT_ASSERT(ret == sizeof(*info));
+ }
+ }
+
+ return sig;
+}
+
+/**
+ * @brief Sends a signal to a specific thread.
+ *
+ * This system call allows a process to send a signal to a specific thread within the same process.
+ * The signal specified by the `sig` parameter will be delivered to the thread with the ID `tid`.
+ * This function is similar to `kill()`, but it targets a specific thread rather than a process.
+ *
+ * @param[in] tid The thread ID to which the signal will be sent. This ID identifies the target thread within the same process.
+ * @param[in] sig The signal number to be sent to the specified thread. The signal can be any valid signal number.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note The `sig` parameter must be a valid signal number. It can range from `1` to `31`, or be one of the predefined signal constants like `SIGKILL`, `SIGTERM`, etc.
+ * If the target thread does not exist or is not eligible to receive the signal, the function will fail.
+ *
+ * @warning If an invalid signal number is provided or the target thread does not exist, an error will be returned.
+ * Be careful when sending signals, as some signals (e.g., `SIGKILL`) can immediately terminate the target thread.
+ *
+ * @see sys_kill(), sys_sigaction()
+ */
+sysret_t sys_tkill(int tid, int sig)
+{
+#ifdef ARCH_MM_MMU
+ rt_thread_t thread;
+ sysret_t ret;
+
+ /**
+ * Brief: Match a tid and do the kill
+ *
+ * Note: Critical Section
+ * - the thread (READ. may be released at the meantime; protected by locked)
+ */
+ thread = lwp_tid_get_thread_and_inc_ref(tid);
+ ret = lwp_thread_signal_kill(thread, sig, SI_USER, 0);
+ lwp_tid_dec_ref(thread);
+
+ return ret;
+#else
+ return lwp_thread_kill((rt_thread_t)tid, sig);
+#endif
+}
+
+/**
+ * @brief Manipulates the signal mask for the current thread.
+ *
+ * This function allows a thread to modify its signal mask, which controls which signals are blocked (prevented from delivery).
+ * The signal mask can be modified by adding, removing, or setting the signal set as a whole, depending on the `how` parameter.
+ * The `sigset` specifies the signals to be manipulated, and the current signal mask before modification can be retrieved in `oset`.
+ *
+ * @param[in] how The operation to perform on the signal mask. It can be one of the following values:
+ * - `SIG_BLOCK`: Add the signals in `sigset` to the current mask (block those signals).
+ * - `SIG_UNBLOCK`: Remove the signals in `sigset` from the current mask (unblock those signals).
+ * - `SIG_SETMASK`: Set the signal mask to the signals specified in `sigset` (replace the current mask).
+ * @param[in] sigset A pointer to an `lwp_sigset_t` structure that specifies the set of signals to be manipulated.
+ * Signals in this set will be added, removed, or set in the current thread's signal mask based on the `how` parameter.
+ * @param[out] oset A pointer to an `lwp_sigset_t` structure where the previous signal mask will be stored.
+ * This allows the caller to restore the previous mask if needed.
+ * @param[in] size The size of the `lwp_sigset_t` structure. This ensures that the correct structure size is used during signal mask manipulation.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note The `sigset` structure should contain only valid signal numbers. If `how` is `SIG_SETMASK`, the entire signal mask will be replaced by the contents of `sigset`.
+ * If `how` is `SIG_BLOCK` or `SIG_UNBLOCK`, the signals in `sigset` will be added or removed from the current mask, respectively.
+ *
+ * @warning Be cautious when modifying the signal mask, as blocking signals can cause the thread to miss important signals.
+ * If a signal is blocked, it will not be delivered to the thread until it is unblocked, or the thread is explicitly made to handle it.
+ *
+ * @see sys_sigaction(), sys_thread_sigpending()
+ */
+sysret_t sys_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset, size_t size)
+{
+ int ret = -1;
+ lwp_sigset_t *pnewset = RT_NULL, *poldset = RT_NULL;
+#ifdef ARCH_MM_MMU
+ lwp_sigset_t newset, oldset;
+#endif /* ARCH_MM_MMU */
+
+ if (!size)
+ {
+ return -EINVAL;
+ }
+ if (!oset && !sigset)
+ {
+ return -EINVAL;
+ }
+ if (size != sizeof(lwp_sigset_t))
+ {
+ return -EINVAL;
+ }
+ if (oset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = &oldset;
+#else
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = oset;
+#endif
+ }
+ if (sigset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&newset, (void *)sigset, sizeof(lwp_sigset_t));
+ pnewset = &newset;
+#else
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ pnewset = (lwp_sigset_t *)sigset;
+#endif
+ }
+ ret = lwp_thread_signal_mask(rt_thread_self(), mask_command_u2k[how], pnewset, poldset);
+ if (ret < 0)
+ {
+ return ret;
+ }
+#ifdef ARCH_MM_MMU
+ if (oset)
+ {
+ lwp_put_to_user(oset, poldset, sizeof(lwp_sigset_t));
+ }
+#endif
+ return (ret < 0 ? -EFAULT : ret);
+}
+
+#ifndef ARCH_MM_MMU
+
+/**
+ * @brief Sets the signal handler for a specific signal in the current thread.
+ *
+ * This function allows a thread to set a custom signal handler for a specific signal.
+ * When the specified signal is received, the corresponding handler function (`func`) will be invoked.
+ * The handler will be executed in the context of the current thread, allowing it to handle signals as needed.
+ *
+ * @param[in] sig The signal number for which the handler is being set. This should be a valid signal number.
+ * @param[in] func The signal handler function to be set. This function will be called when the specified signal is received.
+ * The signature of `func` should match the expected format for signal handlers.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note The `func` parameter must be a valid function pointer. It will be called when the signal specified by `sig` is received by the thread.
+ * The handler function typically has the signature: `void handler(int sig)`, where `sig` is the signal number.
+ *
+ * @warning Setting a custom signal handler may override any default actions for that signal.
+ * It is important to ensure that the handler function is properly designed to handle the signal appropriately.
+ * For example, some signals may require special handling (e.g., `SIGKILL` cannot be caught).
+ *
+ * @see sys_signal(), sys_lwp_sigaction()
+ */
+sysret_t sys_lwp_sighandler_set(int sig, lwp_sighandler_t func)
+{
+ if (!lwp_user_accessable((void *)func, sizeof(lwp_sighandler_t)))
+ {
+ return -EFAULT;
+ }
+
+ lwp_sighandler_set(sig, func);
+ return 0;
+}
+
+/**
+ * @brief Sets the signal handler for a specific signal in the target thread.
+ *
+ * This function allows setting a custom signal handler for a specific signal within a particular thread.
+ * When the specified signal is delivered to the thread, the corresponding handler function (`func`) will be invoked.
+ * The handler is executed in the context of the thread that receives the signal.
+ *
+ * @param[in] sig The signal number for which the handler is being set. This should be a valid signal number.
+ * @param[in] func The signal handler function to be set. This function will be called when the specified signal is delivered to the target thread.
+ * The handler function should have the signature `void func(int sig)`.
+ *
+ * @return sysret_t Returns `0` on success or a negative error code on failure.
+ *
+ * @note The `func` parameter must be a valid function pointer, and it will be invoked when the signal specified by `sig` is delivered to the target thread.
+ * The handler function typically has the signature: `void handler(int sig)`, where `sig` is the signal number.
+ *
+ * @warning Setting a custom signal handler may override any default actions for that signal.
+ * It is important to ensure that the handler function is properly designed to handle the signal appropriately.
+ * For example, some signals may require special handling (e.g., `SIGKILL` cannot be caught).
+ *
+ * @see sys_thread_sigprocmask(), sys_thread_sigaction(), sys_signal()
+ */
+sysret_t sys_thread_sighandler_set(int sig, lwp_sighandler_t func)
+{
+ if (!lwp_user_accessable((void *)func, sizeof(lwp_sighandler_t)))
+ {
+ return -EFAULT;
+ }
+
+ lwp_thread_sighandler_set(sig, func);
+ return 0;
+}
+#endif /* not defined ARCH_MM_MMU */
+
+/**
+ * @brief Waits for the termination of a child process.
+ *
+ * This function makes the calling process wait until one of its child processes terminates or until a
+ * specified condition is met. The function retrieves information about the terminated child process,
+ * including its exit status, and can also handle other process-related events, such as stopping or
+ * continuing execution.
+ *
+ * @param[in] pid The process ID of the child process to wait for. If `pid` is:
+ * - `-1`: Wait for any child process.
+ * - `0`: Wait for any child process in the same process group.
+ * - > 0: Wait for the child process with the specified process ID.
+ * @param[out] status A pointer to an integer where the exit status of the terminated child process will be stored.
+ * This value provides information about the child's termination status, such as normal exit,
+ * signal termination, etc.
+ * @param[in] options A bitmask of options that control the behavior of the function. It can include:
+ * - `WNOHANG`: Return immediately if no child has exited.
+ * - `WUNTRACED`: Report status of stopped child processes.
+ * - Other flags can be defined depending on the implementation.
+ *
+ * @return sysret_t Returns the process ID of the child process that terminated on success, or a negative error code on failure.
+ *
+ * @note The `status` argument provides detailed information about the termination of the child process. To interpret this
+ * status, macros such as `WIFEXITED()`, `WIFSIGNALED()`, and `WEXITSTATUS()` are commonly used.
+ *
+ * @warning This function should be used carefully when managing child processes, as not properly handling child processes
+ * may lead to zombie processes.
+ *
+ * @see sys_wait(), sys_waitid()
+ */
+sysret_t sys_waitpid(int32_t pid, int *status, int options)
+{
+ int ret = -1;
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)status, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ else
+ {
+ ret = lwp_waitpid(pid, status, options, RT_NULL);
+ }
+#else
+ if (!lwp_user_accessable((void *)status, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ ret = waitpid(pid, status, options);
+#endif
+ return ret;
+}