summaryrefslogtreecommitdiff
path: root/components/lwp/syscall/syscall_process.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/lwp/syscall/syscall_process.c')
-rw-r--r--components/lwp/syscall/syscall_process.c479
1 files changed, 479 insertions, 0 deletions
diff --git a/components/lwp/syscall/syscall_process.c b/components/lwp/syscall/syscall_process.c
new file mode 100644
index 0000000000..9da79959ac
--- /dev/null
+++ b/components/lwp/syscall/syscall_process.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "syscall_internal.h"
+
+/**
+ * @brief Terminates all threads in the current thread group.
+ *
+ * This system call ends execution for all threads within the same thread group,
+ * releasing resources such as memory and file descriptors. It is typically used
+ * in multithreaded environments to ensure a clean exit for the entire process.
+ *
+ * @param value The exit code to be returned to the parent process.
+ * @return sysret_t: return value of the system call execution.
+ */
+sysret_t sys_exit_group(int value)
+{
+ sysret_t rc = 0;
+ lwp_status_t lwp_status;
+ struct rt_lwp *lwp = lwp_self();
+
+ if (lwp)
+ {
+ lwp_status = LWP_CREATE_STAT_EXIT(value);
+ lwp_exit(lwp, lwp_status);
+ }
+ else
+ {
+ LOG_E("Can't find matching process of current thread");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/**
+ * @brief Terminates the calling thread and exits the process.
+ *
+ * This system call ends the execution of the calling thread and the process
+ * it belongs to.
+ *
+ * @param status The exit code to be returned to the parent process.
+ * A value of 0 typically indicates successful execution, while
+ * non-zero values indicate an error or specific exit condition.
+ * @return sysret_t: return value of the system call execution.
+ *
+ * @note Unlike `sys_exit_group`, which terminates all threads in a thread group,
+ * `sys_exit` only terminates the calling thread and the process.
+ */
+sysret_t sys_exit(int status)
+{
+ sysret_t rc = 0;
+ rt_thread_t tid;
+
+ tid = rt_thread_self();
+ if (tid && tid->lwp)
+ {
+ lwp_thread_exit(tid, status);
+ }
+ else
+ {
+ LOG_E("Can't find matching process of current thread");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/**
+ * @brief Replaces the current process with a new process.
+ *
+ * This system call loads a new program into the current process's address space,
+ * replacing the current program with the one specified by `filename`. It passes the
+ * arguments `argv` and environment variables `envp` to the new program. If the execution
+ * is successful, the current process is completely replaced, and no code after the
+ * `sys_exec` call is executed. If an error occurs, the system call returns, and the
+ * current process continues executing.
+ *
+ * @param filename The path to the executable file to be run. This can be an absolute
+ * or relative path.
+ * @param argc The number of arguments passed to the new program. This includes the
+ * executable name itself as the first argument.
+ * @param argv An array of strings (character pointers), where each string is an argument
+ * passed to the new program. The first element (`argv[0]`) is conventionally
+ * the name of the executable.
+ * @param envp An array of strings representing the environment variables for the new
+ * process. The array is terminated by a `NULL` pointer.
+ * @return This function does not return on success, as the current process is replaced.
+ * On failure, it returns error code to indicate the error.
+ *
+ * @note The new process inherits most of the attributes of the current process, such
+ * as file descriptors, unless explicitly modified. It is important that `argv`
+ * and `envp` are properly formatted, and the `filename` points to a valid executable.
+ *
+ * @warning If `filename` is invalid or not an executable, or if the arguments or
+ * environment variables are incorrectly set, the system call will fail and
+ * return `-1`. Ensure that the executable file is accessible and that `argv`
+ * and `envp` are properly constructed.
+ *
+ * @see execve(), execvp(), execv(), execle()
+ */
+sysret_t sys_exec(char *filename, int argc, char **argv, char **envp)
+{
+ int ret = 0;
+ int len = 0;
+ char *kfilename = RT_NULL;
+
+ len = lwp_user_strlen(filename);
+ if (len <= 0)
+ {
+ return -EFAULT;
+ }
+
+ kfilename = (char *)kmem_get(len + 1);
+ if (!kfilename)
+ {
+ return -ENOMEM;
+ }
+
+ if (lwp_get_from_user(kfilename, (void *)filename, len + 1) != (len + 1))
+ {
+ kmem_put(kfilename);
+ return -EFAULT;
+ }
+
+ ret = lwp_execve(kfilename, 0, argc, argv, envp);
+
+ kmem_put(kfilename);
+
+ return ret;
+}
+
+/**
+ * @brief Sends a signal to a process or a group of processes.
+ *
+ * This system call sends the signal specified by `signo` to the process or process group
+ * identified by `pid`. If `pid` is positive, the signal is sent to the process with the
+ * specified process ID. If `pid` is `0`, the signal is sent to all processes in the
+ * same process group as the caller. If `pid` is `-1`, the signal is sent to all processes
+ * except for the caller. If `pid` is less than `-1`, the signal is sent to all processes
+ * in the process group with the process group ID equal to `-pid`.
+ *
+ * @param pid The process ID or process group ID to which the signal is to be sent.
+ * - A positive value sends the signal to the process with that ID.
+ * - `0` sends the signal to all processes in the same process group as the caller.
+ * - `-1` sends the signal to all processes except the caller.
+ * - A negative value sends the signal to all processes in the process group
+ * with the process group ID equal to `-pid`.
+ * @param signo The signal to send. This is an integer value that specifies the signal
+ * type. Common signal values include:
+ * - `SIGTERM` (terminate process)
+ * - `SIGKILL` (force kill process)
+ * - `SIGSTOP` (suspend process)
+ * - `SIGCONT` (resume process)
+ * @return On success, returns `0`. On failure, it returns error code to indicate the error.
+ *
+ * @note Signals are a mechanism for inter-process communication, allowing processes
+ * to send notifications or requests to other processes. The behavior of signals
+ * depends on the signal type and how the receiving process handles them.
+ *
+ * @warning The `signo` value must be a valid signal number. Passing an invalid signal
+ * number or an invalid `pid` may result in an error. Additionally, some signals
+ * (e.g., `SIGKILL`) cannot be caught or ignored by processes.
+ *
+ * @see signal(), killpg(), raise()
+ */
+sysret_t sys_kill(int pid, int signo)
+{
+ rt_err_t kret = 0;
+ sysret_t sysret;
+ struct rt_lwp *lwp = RT_NULL;
+
+ /* handling the semantics of sys_kill */
+ if (pid > 0)
+ {
+ /**
+ * Brief: Match the pid and send signal to the lwp if found
+ * Note: Critical Section
+ * - pid tree (READ. since the lwp is fetch from the pid tree, it must stay there)
+ */
+ lwp_pid_lock_take();
+ lwp = lwp_from_pid_raw_locked(pid);
+ if (lwp)
+ {
+ lwp_ref_inc(lwp);
+ lwp_pid_lock_release();
+ }
+ else
+ {
+ lwp_pid_lock_release();
+ kret = -RT_ENOENT;
+ }
+
+ if (lwp)
+ {
+ kret = lwp_signal_kill(lwp, signo, SI_USER, 0);
+ lwp_ref_dec(lwp);
+ }
+ }
+ else if (pid < -1 || pid == 0)
+ {
+ pid_t pgid = 0;
+ rt_processgroup_t group;
+
+ if (pid == 0)
+ {
+ /**
+ * sig shall be sent to all processes (excluding an unspecified set
+ * of system processes) whose process group ID is equal to the process
+ * group ID of the sender, and for which the process has permission to
+ * send a signal.
+ */
+ pgid = lwp_pgid_get_byprocess(lwp_self());
+ }
+ else
+ {
+ /**
+ * sig shall be sent to all processes (excluding an unspecified set
+ * of system processes) whose process group ID is equal to the absolute
+ * value of pid, and for which the process has permission to send a signal.
+ */
+ pgid = -pid;
+ }
+
+ group = lwp_pgrp_find(pgid);
+ if (group != RT_NULL)
+ {
+ PGRP_LOCK(group);
+ kret = lwp_pgrp_signal_kill(group, signo, SI_USER, 0);
+ PGRP_UNLOCK(group);
+ }
+ else
+ {
+ kret = -ECHILD;
+ }
+ }
+ else if (pid == -1)
+ {
+ /**
+ * sig shall be sent to all processes (excluding an unspecified set
+ * of system processes) for which the process has permission to send
+ * that signal.
+ */
+ kret = lwp_signal_kill_all(signo, SI_USER, 0);
+ }
+
+ switch (kret)
+ {
+ case -RT_ENOENT:
+ case -ECHILD:
+ sysret = -ESRCH;
+ break;
+ case -RT_EINVAL:
+ sysret = -EINVAL;
+ break;
+ case -RT_ENOSYS:
+ sysret = -ENOSYS;
+ break;
+
+ /**
+ * kill() never returns ENOMEM, so return normally to caller.
+ * IEEE Std 1003.1-2017 says the kill() function is successful
+ * if the process has permission to send sig to any of the
+ * processes specified by pid.
+ */
+ case -RT_ENOMEM:
+ default:
+ sysret = 0;
+ }
+ return sysret;
+}
+
+/**
+ * @brief Retrieves the process ID of the calling process.
+ *
+ * This system call returns the process ID (PID) of the calling process. The PID is a
+ * unique identifier assigned by the operating system to each running process. It can
+ * be used to refer to or manipulate the process in subsequent system calls.
+ *
+ * @return The PID of the calling process. On failure, returns `-1` and sets `errno`
+ * to indicate the error (although this function typically does not fail).
+ *
+ * @note The PID returned by this function is a positive integer, and it remains
+ * unique during the lifetime of the process. This value can be used to manage
+ * the process, including sending signals or querying process information.
+ *
+ * @warning This function does not take any arguments and is typically used when
+ * a process needs to obtain its own PID for management or logging purposes.
+ *
+ * @see getppid(), getuid(), getgid()
+ */
+sysret_t sys_getpid(void)
+{
+ return lwp_getpid();
+}
+
+/**
+ * @brief Retrieves the parent process ID of the calling process.
+ *
+ * This system call returns the process ID (PID) of the parent process of the calling process.
+ * The parent process is the process that created the calling process, typically through a
+ * system call like `fork()`. This information can be useful for process management and
+ * for determining the hierarchy of processes.
+ *
+ * @return The PID of the parent process. If the calling process has no parent (for example,
+ * the init process), it typically returns `1` as the PID of the system's "root" process.
+ * On failure, returns `-1` and sets `errno` to indicate the error (although this function
+ * typically does not fail).
+ *
+ * @note The `getppid()` function is commonly used when a process needs to know which
+ * process is responsible for it, or for managing relationships between parent and child processes.
+ *
+ * @warning This function does not take any arguments and is typically used when the
+ * process requires information about its parent. It should not be confused with `getpid()`,
+ * which retrieves the PID of the calling process itself.
+ *
+ * @see getpid(), getuid(), getgid()
+ */
+sysret_t sys_getppid(void)
+{
+ rt_lwp_t process;
+
+ process = lwp_self();
+ if (process->parent == RT_NULL)
+ {
+ LOG_E("%s: process %d has no parent process", __func__, lwp_to_pid(process));
+ return 0;
+ }
+ else
+ {
+ return lwp_to_pid(process->parent);
+ }
+}
+
+/**
+ * @brief Retrieves the priority of a process or process group.
+ *
+ * This system call returns the priority of a process or a process group, depending on
+ * the value of the `which` argument.
+ *
+ * @param which The entity for which the priority is being requested. Possible values include:
+ * - `PRIO_PROCESS`: Retrieves the priority of the process specified by `who`.
+ * - `PRIO_PGRP`: Retrieves the priority of the process group specified by `who`. (Currently not supported.)
+ * - `PRIO_USER`: Retrieves the priority of the user specified by `who` (the user ID). (Currently not supported.)
+ * @param who The ID of the process, process group, or user. The meaning of this parameter
+ * depends on the value of `which`:
+ * - When `which` is `PRIO_PROCESS`, `who` is the process ID (PID) of the process.
+ * - When `which` is `PRIO_PGRP`(Currently not supported.), `who` is the process group ID (PGID).
+ * - When `which` is `PRIO_USER`(Currently not supported.), `who` is the user ID (UID) of the user whose
+ * priority is being queried.
+ * @return On success, returns the priority value (a negative integer indicates a lower
+ * priority).
+ *
+ * @warning Ensure that `which` and `who` are correctly specified to avoid errors.
+ * Invalid values for `which` or `who` may result in an error, and the function
+ * will return `-1`.
+ *
+ * @see setpriority(), getpid(), getppid()
+ */
+sysret_t sys_getpriority(int which, id_t who)
+{
+ long prio = 0xff;
+
+ if (which == PRIO_PROCESS)
+ {
+ struct rt_lwp *lwp = RT_NULL;
+
+ lwp_pid_lock_take();
+ lwp = lwp_from_pid_locked(who);
+
+ if (lwp)
+ {
+ rt_thread_t thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ prio = RT_SCHED_PRIV(thread).current_priority;
+ }
+
+ lwp_pid_lock_release();
+ }
+
+ return prio;
+}
+
+/**
+ * @brief Sets the priority of a process, process group, or user.
+ *
+ * This system call sets the priority of a process, process group, or user, depending
+ * on the value of the `which` argument. The priority is used by the operating system
+ * for scheduling processes. Lower numerical values represent higher priority in many
+ * systems, and the priority range may be system-specific.
+ *
+ * @param which The entity for which the priority is being set. Possible values include:
+ * - `PRIO_PROCESS`: Sets the priority of the process specified by `who`.
+ * - `PRIO_PGRP`: Sets the priority of the process group specified by `who`.(Currently not supported.)
+ * - `PRIO_USER`: Sets the priority of the user specified by `who` (the user ID).(Currently not supported.)
+ * @param who The ID of the process, process group, or user for which the priority is being set.
+ * The meaning of this parameter depends on the value of `which`:
+ * - When `which` is `PRIO_PROCESS`, `who` is the process ID (PID) of the process.
+ * - When `which` is `PRIO_PGRP`(Currently not supported.) , `who` is the process group ID (PGID).
+ * - When `which` is `PRIO_USER`(Currently not supported.) , `who` is the user ID (UID) of the user whose priority
+ * is being set.
+ * @param prio The priority value to set.
+ * @return On success, returns `0`. On failure, returns `-1`.
+ *
+ * @note This function modifies the priority of the specified process, process group, or user.
+ * The priority value is system-specific and may vary based on the system's scheduling
+ * policies. Ensure that the specified priority is within the acceptable range.
+ *
+ * @warning Ensure that `which`, `who`, and `prio` are valid. Invalid values for these
+ * parameters can result in errors, and the system call will return `-1`.
+ *
+ * @see getpriority(), getpid(), getppid()
+ */
+sysret_t sys_setpriority(int which, id_t who, int prio)
+{
+ if (which == PRIO_PROCESS)
+ {
+ struct rt_lwp *lwp = RT_NULL;
+
+ lwp_pid_lock_take();
+ lwp = lwp_from_pid_locked(who);
+
+ if (lwp && prio >= 0 && prio < RT_THREAD_PRIORITY_MAX)
+ {
+ rt_list_t *list;
+ rt_thread_t thread;
+ for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
+ {
+ thread = rt_list_entry(list, struct rt_thread, sibling);
+ rt_thread_control(thread, RT_THREAD_CTRL_RESET_PRIORITY, &prio);
+ }
+ lwp_pid_lock_release();
+ return 0;
+ }
+ else
+ {
+ lwp_pid_lock_release();
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * @brief Waits for a process to change state.
+ *
+ * This function suspends the execution of the calling process until one of its child processes terminates
+ * or a specified process (identified by `pid`) changes its state. The function returns the process ID of the child
+ * process that terminated, and provides information about its exit status and resource usage.
+ *
+ * @param[in] pid The process ID of the child process to wait for. The behavior of this parameter can be one of the following:
+ * - `pid > 0`: Wait for the child process with the specified PID.
+ * - `pid == 0`: Wait for any child process in the same process group.
+ * - `pid == -1`: Wait for any child process (default behavior).
+ * - `pid < -1`: Wait for any child process in the specified process group.
+ *
+ * @param[out] status A pointer to an integer where the exit status of the terminated child process will be stored.
+ * This status can be interpreted using macros such as `WIFEXITED` or `WIFSIGNALED`.
+ *
+ * @param[in] options Options for the wait operation, which can include:
+ * - `WNOHANG`: Return immediately if no child has exited.
+ * - `WUNTRACED`: Return if a child has stopped, but not yet terminated.
+ *
+ * @param[out] ru A pointer to a `struct rusage` where resource usage information of the child process will be stored.
+ * This includes information such as CPU time consumed by the child process.
+ *
+ * @return sysret_t Returns the process ID of the terminated child on success. In case of failure, a negative error code is returned.
+ *
+ * @note This function is useful for monitoring and cleaning up child processes in parent-child relationships.
+ * The `status` value can be further analyzed to determine if the child process terminated normally or due to a signal.
+ *
+ * @see sys_waitpid(), sys_fork(), sys_exit()
+ */
+sysret_t sys_wait4(pid_t pid, int *status, int options, struct rusage *ru)
+{
+ return lwp_waitpid(pid, status, options, ru);
+}