diff --git a/kernel/Makefile b/kernel/Makefile index 973f940b..18d4070f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -128,6 +128,7 @@ pci.o \ pipe.o \ poll.o \ process.o \ +psctl.o \ ptable.o \ random.o \ refcount.o \ diff --git a/kernel/include/sortix/kernel/process.h b/kernel/include/sortix/kernel/process.h index dc3329ff..95622688 100644 --- a/kernel/include/sortix/kernel/process.h +++ b/kernel/include/sortix/kernel/process.h @@ -117,7 +117,7 @@ public: void SetRoot(Ref newroot); void SetCWD(Ref newcwd); -private: +public: // A process may only access its parent if parentlock is locked. A process // may only use its list of children if childlock is locked. A process may // not access its sibling processes. diff --git a/kernel/include/sortix/kernel/ptable.h b/kernel/include/sortix/kernel/ptable.h index 14edab3a..cf53145d 100644 --- a/kernel/include/sortix/kernel/ptable.h +++ b/kernel/include/sortix/kernel/ptable.h @@ -48,6 +48,8 @@ public: Process* Get(pid_t pid); pid_t Allocate(Process* process); void Free(pid_t pid); + pid_t Prev(pid_t pid); + pid_t Next(pid_t pid); private: kthread_mutex_t ptablelock; diff --git a/kernel/include/sortix/kernel/syscall.h b/kernel/include/sortix/kernel/syscall.h index 799a7bf1..e62ab625 100644 --- a/kernel/include/sortix/kernel/syscall.h +++ b/kernel/include/sortix/kernel/syscall.h @@ -122,6 +122,7 @@ int sys_ppoll(struct pollfd*, size_t, const struct timespec*, const sigset_t*); ssize_t sys_pread(int, void*, size_t, off_t); ssize_t sys_preadv(int, const struct iovec*, int, off_t); int sys_prlimit(pid_t, int, const struct rlimit*, struct rlimit*); +int sys_psctl(pid_t, int, void*); ssize_t sys_pwrite(int, const void*, size_t, off_t); ssize_t sys_pwritev(int, const struct iovec*, int, off_t); int sys_raise(int); diff --git a/kernel/include/sortix/psctl.h b/kernel/include/sortix/psctl.h new file mode 100644 index 00000000..326976e5 --- /dev/null +++ b/kernel/include/sortix/psctl.h @@ -0,0 +1,105 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2015. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + sortix/psctl.h + Process control interface. + +*******************************************************************************/ + +#ifndef INCLUDE_SORTIX_PSCTL_H +#define INCLUDE_SORTIX_PSCTL_H + +#include + +#include + +#include + +#ifndef __size_t_defined +#define __size_t_defined +#define __need_size_t +#include +#endif + +#ifndef __gid_t_defined +#define __gid_t_defined +typedef __gid_t gid_t; +#endif + +#ifndef __pid_t_defined +#define __pid_t_defined +typedef __pid_t pid_t; +#endif + +#ifndef __uid_t_defined +#define __uid_t_defined +typedef __uid_t uid_t; +#endif + +#define __PSCTL(s, v) (sizeof(struct s) << 16 | (v)) + +#define PSCTL_PREV_PID __PSCTL(psctl_prev_pid, 1) +struct psctl_prev_pid +{ + pid_t prev_pid; +}; + +#define PSCTL_NEXT_PID __PSCTL(psctl_next_pid, 2) +struct psctl_next_pid +{ + pid_t next_pid; +}; + +#define PSCTL_STAT __PSCTL(psctl_stat, 3) +struct psctl_stat +{ + pid_t pid; + pid_t ppid; + pid_t ppid_prev; + pid_t ppid_next; + pid_t ppid_first; + pid_t pgid; + pid_t pgid_prev; + pid_t pgid_next; + pid_t pgid_first; + pid_t sid; + pid_t sid_prev; + pid_t sid_next; + pid_t sid_first; + pid_t init; + pid_t init_prev; + pid_t init_next; + pid_t init_first; + uid_t uid; + uid_t euid; + gid_t gid; + gid_t egid; + int status; + int nice; + struct tmns tmns; +}; + +#define PSCTL_PROGRAM_PATH __PSCTL(psctl_program_path, 4) +struct psctl_program_path +{ + char* buffer; + size_t size; +}; + +#endif diff --git a/kernel/include/sortix/syscall.h b/kernel/include/sortix/syscall.h index 234fcc98..53634be4 100644 --- a/kernel/include/sortix/syscall.h +++ b/kernel/include/sortix/syscall.h @@ -178,6 +178,8 @@ #define SYSCALL_UNMOUNTAT 150 #define SYSCALL_FSM_MOUNTAT 151 #define SYSCALL_CLOSEFROM 152 -#define SYSCALL_MAX_NUM 153 /* index of highest constant + 1 */ +#define SYSCALL_RESERVED1 153 +#define SYSCALL_PSCTL 154 +#define SYSCALL_MAX_NUM 155 /* index of highest constant + 1 */ #endif diff --git a/kernel/psctl.cpp b/kernel/psctl.cpp new file mode 100644 index 00000000..28317990 --- /dev/null +++ b/kernel/psctl.cpp @@ -0,0 +1,166 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2015. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + psctl.cpp + Process control interface. + +*******************************************************************************/ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Sortix { + +int sys_psctl(pid_t pid, int request, void* ptr) +{ + Ref ptable = CurrentProcess()->GetPTable(); + if ( request == PSCTL_PREV_PID ) + { + struct psctl_prev_pid resp; + memset(&resp, 0, sizeof(resp)); + resp.prev_pid = ptable->Prev(pid); + return CopyToUser(ptr, &resp, sizeof(resp)) ? 0 : -1; + } + else if ( request == PSCTL_NEXT_PID ) + { + struct psctl_next_pid resp; + memset(&resp, 0, sizeof(resp)); + resp.next_pid = ptable->Next(pid); + return CopyToUser(ptr, &resp, sizeof(resp)) ? 0 : -1; + } + // TODO: Scoped lock that prevents zombies from terminating. + Process* process = ptable->Get(pid); + if ( !process ) + return errno = ESRCH, -1; + if ( request == PSCTL_STAT ) + { + struct psctl_stat psst; + memset(&psst, 0, sizeof(psst)); + psst.pid = pid; + kthread_mutex_lock(&process->parentlock); + if ( process->parent ) + { + Process* parent = process->parent; + psst.ppid = parent->pid; + kthread_mutex_unlock(&process->parentlock); + // TODO: Is there a risk of getting a new parent here? + kthread_mutex_lock(&parent->childlock); + psst.ppid_prev = process->prevsibling ? process->prevsibling->pid : -1; + psst.ppid_next = process->nextsibling ? process->nextsibling->pid : -1; + kthread_mutex_unlock(&parent->childlock); + } + else + { + kthread_mutex_unlock(&process->parentlock); + psst.ppid = -1; + psst.ppid_prev = -1; + psst.ppid_next = -1; + } + kthread_mutex_lock(&process->childlock); + psst.ppid_first = process->firstchild ? process->firstchild->pid : -1; + kthread_mutex_unlock(&process->childlock); + kthread_mutex_lock(&process->groupparentlock); + if ( process->group ) + { + Process* group = process->group; + psst.pgid = group->pid; + kthread_mutex_unlock(&process->groupparentlock); + // TODO: Is there a risk of getting a new group here? + kthread_mutex_lock(&group->groupchildlock); + psst.pgid_prev = process->groupprev ? process->groupprev->pid : -1; + psst.pgid_next = process->groupnext ? process->groupnext->pid : -1; + kthread_mutex_unlock(&group->groupchildlock); + } + else + { + kthread_mutex_unlock(&process->groupparentlock); + psst.pgid = -1; + psst.pgid_prev = -1; + psst.pgid_next = -1; + } + kthread_mutex_lock(&process->groupchildlock); + psst.pgid_first = process->groupfirst ? process->groupfirst->pid : -1; + kthread_mutex_unlock(&process->groupchildlock); + // TODO: Implement sessions. + psst.sid = 1; + psst.sid_prev = ptable->Prev(pid); + psst.sid_next = ptable->Next(pid); + psst.sid_first = pid == 1 ? 1 : -1; + // TODO: Implement init groupings. + psst.init = 1; + psst.init_prev = ptable->Prev(pid); + psst.init_next = ptable->Next(pid); + psst.init_first = pid == 1 ? 1 : -1; + kthread_mutex_lock(&process->threadlock); + psst.status = process->exit_code; + kthread_mutex_unlock(&process->threadlock); + kthread_mutex_lock(&process->nicelock); + psst.nice = process->nice; + kthread_mutex_unlock(&process->nicelock); + // Note: It is safe to access the clocks in this manner as each of them + // are locked by disabling interrupts. This is perhaps not + // SMP-ready, but it will do for now. + Interrupt::Disable(); + psst.tmns.tmns_utime = process->execute_clock.current_time; + psst.tmns.tmns_stime = process->system_clock.current_time; + psst.tmns.tmns_cutime = process->child_execute_clock.current_time; + psst.tmns.tmns_cstime = process->child_system_clock.current_time; + Interrupt::Enable(); + return CopyToUser(ptr, &psst, sizeof(psst)) ? 0 : -1; + } + else if ( request == PSCTL_PROGRAM_PATH ) + { + struct psctl_program_path ctl; + if ( !CopyFromUser(&ctl, ptr, sizeof(ctl)) ) + return -1; + // TODO: program_image_path is not properly protected at this time. + const char* path = process->program_image_path; + if ( !path ) + path = ""; + size_t size = strlen(path) + 1; + struct psctl_program_path resp = ctl; + resp.size = size; + if ( !CopyToUser(ptr, &resp, sizeof(resp)) ) + return -1; + if ( ctl.buffer ) + { + if ( ctl.size < size ) + return errno = ERANGE, -1; + if ( !CopyToUser(ctl.buffer, path, size) ) + return -1; + } + return 0; + } + return errno = EINVAL, -1; +} + +} // namespace Sortix diff --git a/kernel/ptable.cpp b/kernel/ptable.cpp index 332e5d62..f0602294 100644 --- a/kernel/ptable.cpp +++ b/kernel/ptable.cpp @@ -29,11 +29,11 @@ #include #include +#include #include #include // TODO: Process memory ownership needs to be reference counted. -// TODO: There is no proper way to iterate all the existing processes. // TODO: This implementation is rather run-time inefficient. // TODO: The Free method potentially leaks memory as the ptable is never shrunk. // TODO: The next_pid counter could potentially overflow. @@ -100,4 +100,32 @@ void ProcessTable::Free(pid_t pid) assert(false); } +pid_t ProcessTable::Prev(pid_t pid) +{ + ScopedLock lock(&ptablelock); + pid_t result = -1; + for ( size_t i = 0; i < entries_used; i++ ) + { + if ( pid <= entries[i].process->pid ) + continue; + if ( result == -1 || result < entries[i].process->pid ) + result = entries[i].process->pid; + } + return result; +} + +pid_t ProcessTable::Next(pid_t pid) +{ + ScopedLock lock(&ptablelock); + pid_t result = -1; + for ( size_t i = 0; i < entries_used; i++ ) + { + if ( entries[i].process->pid <= pid ) + continue; + if ( result == -1 || entries[i].process->pid < result ) + result = entries[i].process->pid; + } + return result; +} + } // namespace Sortix diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 693b8d2e..2537d27e 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -188,6 +188,8 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] = [SYSCALL_UNMOUNTAT] = (void*) sys_unmountat, [SYSCALL_FSM_MOUNTAT] = (void*) sys_fsm_mountat, [SYSCALL_CLOSEFROM] = (void*) sys_closefrom, + [SYSCALL_RESERVED1] = (void*) sys_bad_syscall, + [SYSCALL_PSCTL] = (void*) sys_psctl, [SYSCALL_MAX_NUM] = (void*) sys_bad_syscall, }; } /* extern "C" */ diff --git a/libc/Makefile b/libc/Makefile index bd50424f..1f8443b9 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -388,6 +388,7 @@ netdb/setprotoent.o \ netdb/setservent.o \ poll/poll.o \ poll/ppoll.o \ +psctl/psctl.o \ pwd/endpwent.o \ pwd/fgetpwent.o \ pwd/fgetpwent_r.o \ diff --git a/libc/include/psctl.h b/libc/include/psctl.h new file mode 100644 index 00000000..1ad6b87b --- /dev/null +++ b/libc/include/psctl.h @@ -0,0 +1,49 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2015. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + psctl.h + Process control interface. + +*******************************************************************************/ + +#ifndef INCLUDE_SYS_IOCTL_H +#define INCLUDE_SYS_IOCTL_H + +#include + +#include + +#include + +#ifndef __pid_t_defined +#define __pid_t_defined +typedef __pid_t pid_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int psctl(pid_t, int, ...); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/libc/psctl/psctl.cpp b/libc/psctl/psctl.cpp new file mode 100644 index 00000000..bbd476db --- /dev/null +++ b/libc/psctl/psctl.cpp @@ -0,0 +1,39 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2015. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + psctl/psctl.cpp + Process control interface. + +*******************************************************************************/ + +#include + +#include +#include + +DEFN_SYSCALL3(int, sys_psctl, SYSCALL_PSCTL, pid_t, int, void*); + +extern "C" int psctl(pid_t pid, int request, ...) +{ + va_list ap; + va_start(ap, request); + void* ptr = va_arg(ap, void*); + va_end(ap); + return sys_psctl(pid, request, ptr); +}