diff --git a/ce/Makefile b/ce/Makefile index a3bbf4e..9bb7685 100644 --- a/ce/Makefile +++ b/ce/Makefile @@ -1,5 +1,6 @@ include ../make/ufuncs.mk $(eval $(call add_lib,libstring)) +$(eval $(call add_lib,libprocess)) include ../make/user.mk diff --git a/ce/ce.c b/ce/ce.c index b60ff26..295c5cd 100644 --- a/ce/ce.c +++ b/ce/ce.c @@ -1,4 +1,14 @@ -#include +#include #include -void app_main (void) {} +void app_main (void) { + int e_pid = get_exec_pid (); + int e_pgid = get_procgroup (e_pid); + + for (;;) { + char ch; + + mail_receive (&ch, 1); + mail_send (e_pgid, &ch, 1); + } +} diff --git a/include/m/syscall_defs.h b/include/m/syscall_defs.h index d08a6e8..ad630ea 100644 --- a/include/m/syscall_defs.h +++ b/include/m/syscall_defs.h @@ -18,5 +18,9 @@ #define SYS_CLOSE 15 #define SYS_READ 16 #define SYS_DESCRIBE 17 +#define SYS_MAIL_SEND 18 +#define SYS_MAIL_RECEIVE 19 +#define SYS_GET_PROCGROUP 20 +#define SYS_GET_EXEC_PID 21 #endif // _M_SYSCALL_DEFS_H diff --git a/init/init.c b/init/init.c index d4114bf..6ad77fa 100644 --- a/init/init.c +++ b/init/init.c @@ -6,58 +6,20 @@ #include #include -#define MUTEX 2000 - -__thread volatile char letter = 'c'; - -void app_proc (void) { - char arg_letter = (char)(uintptr_t)process_argument (); - - letter = arg_letter; - - for (;;) { - mutex_lock (MUTEX); - - for (int i = 0; i < 3; i++) - test (letter); - /* terminal_print (&letter, 1); */ - - for (volatile int i = 0; i < 1000 * 1000; i++) - ; - - mutex_unlock (MUTEX); - } - - process_quit (); -} - void app_main (void) { - mutex_create (MUTEX); - - letter = 'a'; - - /* process_exec ("ramdisk:/ce"); */ - - /* process_spawn (&app_proc, (void*)'b'); */ - /* process_spawn (&app_proc, (void*)'c'); */ - /* process_spawn (&app_proc, (void*)'d'); */ - - const char* path = "ramdisk:/init.cmd"; - char buffer[1024]; - memset (buffer, 0, sizeof (buffer)); - - open (path); - read (path, 0, (uint8_t*)buffer, sizeof (buffer)); - close (path); - - terminal_print (buffer, strlen (buffer)); + int ce_pid = exec ("ramdisk:/ce"); + int ce_pgid = get_procgroup (ce_pid); for (;;) { int ch = kb_read_key (); - if (ch < 0) + if (ch <= 0) continue; - terminal_print ((char*)&ch, 1); + mail_send (ce_pgid, (uint8_t*)&ch, 1); + + char rcv; + mail_receive (&rcv, 1); + terminal_print (&rcv, 1); } } diff --git a/kernel/amd64/proc.c b/kernel/amd64/proc.c index 48df073..52d71e4 100644 --- a/kernel/amd64/proc.c +++ b/kernel/amd64/proc.c @@ -55,6 +55,8 @@ struct proc* proc_from_elf (uint8_t* elf_contents) { proc->pdata.regs.cs = GDT_UCODE | 0x03; proc->pdata.regs.rip = aux.entry; + proc->exec_pid = -1; + return proc; } @@ -92,6 +94,8 @@ struct proc* proc_clone (struct proc* proto, uintptr_t vstack_top, uintptr_t ent proc_init_tls (proc); + proc->exec_pid = -1; + return proc; } diff --git a/kernel/proc/mail.c b/kernel/proc/mail.c new file mode 100644 index 0000000..31d0991 --- /dev/null +++ b/kernel/proc/mail.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool proc_cleanup_resource_mail (struct proc_resource* resource, struct cpu** reschedule_cpu) { + struct proc_mail* mail = &resource->u.mail; + bool reschedule = PROC_NO_RESCHEDULE; + + spin_lock (&mail->resource->lock); + + if (mail->pending_mesg != NULL) + free (mail->pending_mesg); + + mail->pending_mesg_size = 0; + + spin_lock (&mail->send_sq.lock); + + while (mail->send_sq.proc_list != NULL) { + struct list_node_link* node = mail->send_sq.proc_list; + struct proc_sq_entry* sq_entry = list_entry (node, struct proc_sq_entry, sq_link); + struct proc* suspended_proc = sq_entry->proc; + + spin_unlock (&mail->send_sq.lock); + spin_unlock (&mail->resource->lock); + + reschedule = reschedule || proc_sq_resume (suspended_proc, sq_entry, reschedule_cpu); + + spin_lock (&mail->resource->lock); + spin_lock (&mail->send_sq.lock); + } + + spin_unlock (&mail->send_sq.lock); + + spin_unlock (&mail->resource->lock); + + return reschedule; +} + +bool proc_mail_send (struct proc* proc, struct proc_mail* mail, struct cpu** reschedule_cpu, + void* data, size_t data_size) { + spin_lock (&mail->resource->lock); + spin_lock (&mail->recv_sq.lock); + + /* if receiver available, hand off directly */ + struct list_node_link* node = mail->recv_sq.proc_list; + + if (node != NULL) { + struct proc_sq_entry* sq_entry = list_entry (node, struct proc_sq_entry, sq_link); + struct proc* resumed_proc = sq_entry->proc; + + spin_unlock (&mail->recv_sq.lock); + spin_unlock (&mail->resource->lock); + + spin_lock (&proc->lock); + + if (resumed_proc->mail_recv_buffer != NULL) { + size_t copy_size = + (data_size < resumed_proc->mail_recv_size) ? data_size : resumed_proc->mail_recv_size; + memcpy (resumed_proc->mail_recv_buffer, data, copy_size); + + resumed_proc->mail_recv_buffer = NULL; + resumed_proc->mail_recv_size = 0; + } + + spin_unlock (&proc->lock); + + return proc_sq_resume (resumed_proc, sq_entry, reschedule_cpu); + } + + spin_unlock (&mail->recv_sq.lock); + + /* mail full */ + if (mail->pending_mesg != NULL) { + return proc_sq_suspend (proc, &mail->send_sq, &mail->resource->lock, reschedule_cpu); + } + + /* mail is empty and nobody is waiting */ + mail->pending_mesg = malloc (data_size); + memcpy (mail->pending_mesg, data, data_size); + mail->pending_mesg_size = data_size; + + spin_unlock (&mail->resource->lock); + + return PROC_NO_RESCHEDULE; +} + +bool proc_mail_receive (struct proc* proc, struct proc_mail* mail, struct cpu** reschedule_cpu, + void* recv_buffer, size_t recv_size) { + spin_lock (&proc->lock); + proc->mail_recv_buffer = recv_buffer; + proc->mail_recv_size = recv_size; + spin_unlock (&proc->lock); + + spin_lock (&mail->resource->lock); + + /* consume mesg if available */ + if (mail->pending_mesg != NULL) { + memcpy (recv_buffer, mail->pending_mesg, recv_size); + free (mail->pending_mesg); + mail->pending_mesg = NULL; + mail->pending_mesg_size = 0; + + /* check for suspended sender */ + spin_lock (&mail->send_sq.lock); + + struct list_node_link* node = mail->send_sq.proc_list; + + if (node != NULL) { + struct proc_sq_entry* sq_entry = list_entry (node, struct proc_sq_entry, sq_link); + struct proc* resumed_proc = sq_entry->proc; + + spin_unlock (&mail->send_sq.lock); + spin_unlock (&mail->resource->lock); + + return proc_sq_resume (resumed_proc, sq_entry, reschedule_cpu); + } + + spin_unlock (&mail->send_sq.lock); + spin_unlock (&mail->resource->lock); + + return PROC_NO_RESCHEDULE; + } + + /* nothing to receive */ + return proc_sq_suspend (proc, &mail->recv_sq, &mail->resource->lock, reschedule_cpu); +} diff --git a/kernel/proc/mail.h b/kernel/proc/mail.h new file mode 100644 index 0000000..d58c401 --- /dev/null +++ b/kernel/proc/mail.h @@ -0,0 +1,26 @@ +#ifndef _KERNEL_PROC_MAIL_H +#define _KERNEL_PROC_MAIL_H + +#include +#include + +struct proc; +struct proc_resource; +struct cpu; + +struct proc_mail { + struct proc_resource* resource; + + struct proc_suspension_q send_sq; + struct proc_suspension_q recv_sq; + void* pending_mesg; + size_t pending_mesg_size; +}; + +bool proc_cleanup_resource_mail (struct proc_resource* resource, struct cpu** reschedule_cpu); +bool proc_mail_send (struct proc* proc, struct proc_mail* mail, struct cpu** reschedule_cpu, + void* data, size_t data_size); +bool proc_mail_receive (struct proc* proc, struct proc_mail* mail, struct cpu** reschedule_cpu, + void* recv_buffer, size_t recv_size); + +#endif // _KERNEL_PROC_MAIL_H diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index d7a2d78..054fb1d 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -32,6 +32,7 @@ struct cpu; struct proc { int pid; + int exec_pid; struct rb_node_link proc_tree_link; struct rb_node_link procgroup_memb_tree_link; struct list_node_link cpu_run_q_link; @@ -44,6 +45,8 @@ struct proc { struct cpu* cpu; atomic_int state; uintptr_t uvaddr_argument; + void* mail_recv_buffer; + size_t mail_recv_size; }; void proc_sched (void); diff --git a/kernel/proc/procgroup.c b/kernel/proc/procgroup.c index 2ea2bd3..b2dd17f 100644 --- a/kernel/proc/procgroup.c +++ b/kernel/proc/procgroup.c @@ -14,6 +14,16 @@ static struct rb_node_link* procgroup_tree = NULL; static spin_lock_t procgroup_tree_lock = SPIN_LOCK_INIT; static atomic_int pgids = 0; +struct procgroup* procgroup_find (int pgid) { + struct procgroup* procgroup = NULL; + + spin_lock (&procgroup_tree_lock); + rbtree_find (struct procgroup, &procgroup_tree, pgid, procgroup, procgroup_tree_link, pgid); + spin_unlock (&procgroup_tree_lock); + + return procgroup; +} + uintptr_t procgroup_map (struct procgroup* procgroup, uintptr_t vaddr, size_t pages, uint32_t flags, uintptr_t* out_paddr) { spin_lock (&procgroup->lock); @@ -141,6 +151,11 @@ struct procgroup* procgroup_create (void) { procgroup->pd.cr3_paddr = mm_alloc_user_pd_phys (); procgroup->map_base = PROC_MAP_BASE; + if (proc_create_resource_mail (procgroup, 1) == NULL) { + free (procgroup); + return NULL; + } + spin_lock (&procgroup_tree_lock); rbtree_insert (struct procgroup, &procgroup_tree, &procgroup->procgroup_tree_link, procgroup_tree_link, pgid); diff --git a/kernel/proc/procgroup.h b/kernel/proc/procgroup.h index 4dcc889..270ed45 100644 --- a/kernel/proc/procgroup.h +++ b/kernel/proc/procgroup.h @@ -40,5 +40,6 @@ void procgroup_detach (struct procgroup* procgroup, struct proc* proc); uintptr_t procgroup_map (struct procgroup* procgroup, uintptr_t vaddr, size_t pages, uint32_t flags, uintptr_t* out_paddr); bool procgroup_unmap (struct procgroup* procgroup, uintptr_t start_vaddr, size_t pages); +struct procgroup* procgroup_find (int pgid); #endif // _KERNEL_PROC_PROCGROUP_H diff --git a/kernel/proc/resource.c b/kernel/proc/resource.c index 760e0b1..95b5804 100644 --- a/kernel/proc/resource.c +++ b/kernel/proc/resource.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,32 @@ struct proc_resource* proc_create_resource_mutex (struct procgroup* procgroup, i return resource; } +struct proc_resource* proc_create_resource_mail (struct procgroup* procgroup, int rid) { + struct proc_resource* resource; + + resource = proc_find_resource (procgroup, rid); + if (resource != NULL) + return resource; + + resource = malloc (sizeof (*resource)); + if (resource == NULL) + return NULL; + + memset (resource, 0, sizeof (*resource)); + resource->lock = SPIN_LOCK_INIT; + resource->ops.cleanup = &proc_cleanup_resource_mail; + resource->u.mail.resource = resource; + resource->rid = rid; + resource->type = PR_MAIL; + + spin_lock (&procgroup->lock); + rbtree_insert (struct proc_resource, &procgroup->resource_tree, &resource->resource_tree_link, + resource_tree_link, rid); + spin_unlock (&procgroup->lock); + + return resource; +} + bool proc_delete_resource (struct proc_resource* resource, struct cpu** reschedule_cpu) { bool reschedule = resource->ops.cleanup (resource, reschedule_cpu); free (resource); diff --git a/kernel/proc/resource.h b/kernel/proc/resource.h index 89a8e45..d3a61d6 100644 --- a/kernel/proc/resource.h +++ b/kernel/proc/resource.h @@ -4,10 +4,12 @@ #include #include #include +#include #include #include -#define PR_MUTEX 1 +#define PR_MUTEX 0 +#define PR_MAIL 1 struct proc; struct procgroup; @@ -20,6 +22,7 @@ struct proc_resource { struct rb_node_link resource_tree_link; union { struct proc_mutex mutex; + struct proc_mail mail; } u; struct { bool (*cleanup) (struct proc_resource* resource, struct cpu** reschedule_cpu); @@ -28,6 +31,7 @@ struct proc_resource { struct proc_resource* proc_find_resource (struct procgroup* procgroup, int rid); struct proc_resource* proc_create_resource_mutex (struct procgroup* procgroup, int rid); +struct proc_resource* proc_create_resource_mail (struct procgroup* procgroup, int rid); bool proc_delete_resource (struct proc_resource* resource, struct cpu** reschedule_cpu); #endif // _KERNEL_PROC_RESOURCE_H diff --git a/kernel/proc/src.mk b/kernel/proc/src.mk index a090d65..5b1510f 100644 --- a/kernel/proc/src.mk +++ b/kernel/proc/src.mk @@ -2,10 +2,12 @@ c += proc/proc.c \ proc/resource.c \ proc/mutex.c \ proc/procgroup.c \ - proc/suspension_q.c + proc/suspension_q.c \ + proc/mail.c o += proc/proc.o \ proc/resource.o \ proc/mutex.o \ proc/procgroup.o \ - proc/suspension_q.o + proc/suspension_q.o \ + proc/mail.o diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 809d774..a9622a3 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -171,6 +172,58 @@ DEFINE_SYSCALL (sys_mutex_unlock) { return SYSRESULT (ST_OK); } +/* int mail_send (int pgid, void* mesg, size_t mesg_size) */ +DEFINE_SYSCALL (sys_mail_send) { + int pgid = (int)a1; + uintptr_t uvaddr_mesg = a2; + size_t mesg_size = (size_t)a3; + + void* mesg = sys_get_user_buffer (proc, uvaddr_mesg, mesg_size); + + if (mesg == NULL) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + struct procgroup* procgroup = procgroup_find (pgid); + + if (procgroup == NULL) + return SYSRESULT (-ST_NOT_FOUND); + + struct proc_resource* mail_resource = proc_find_resource (procgroup, 1); + + if (mail_resource == NULL) + return SYSRESULT (-ST_NOT_FOUND); + + if (proc_mail_send (proc, &mail_resource->u.mail, reschedule_cpu, mesg, mesg_size) == + PROC_NEED_RESCHEDULE) { + *reschedule = true; + } + + return SYSRESULT (ST_OK); +} + +/* int mail_receive (void* recv_mesg, size_t mesg_size) */ +DEFINE_SYSCALL (sys_mail_receive) { + uintptr_t uvaddr_mesg = a1; + size_t mesg_size = (size_t)a2; + + void* mesg = sys_get_user_buffer (proc, uvaddr_mesg, mesg_size); + + if (mesg == NULL) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + struct proc_resource* mail_resource = proc_find_resource (proc->procgroup, 1); + + if (mail_resource == NULL) + return SYSRESULT (-ST_NOT_FOUND); + + if (proc_mail_receive (proc, &mail_resource->u.mail, reschedule_cpu, mesg, mesg_size) == + PROC_NEED_RESCHEDULE) { + *reschedule = true; + } + + return SYSRESULT (ST_OK); +} + /* int device_do (int device_id, int cmd, void* a1, void* a2, void* a3, void* a4) */ DEFINE_SYSCALL (sys_device_do) { struct limine_hhdm_response* hhdm = limine_hhdm_request.response; @@ -255,6 +308,7 @@ DEFINE_SYSCALL (sys_exec) { return SYSRESULT (-ST_EXEC_ERROR); int pid = new->pid; + new->exec_pid = proc->pid; if (proc_register (new, reschedule_cpu) == PROC_NEED_RESCHEDULE) *reschedule = true; @@ -381,6 +435,18 @@ DEFINE_SYSCALL (sys_describe) { return SYSRESULT (vfs_describe (proc->procgroup, mountpoint, subpath, desc)); } +/* int get_procgroup (int pid) */ +DEFINE_SYSCALL (sys_get_procgroup) { + int pid = (int)a1; + + struct proc* target_proc = proc_find_pid (pid); + + return SYSRESULT (target_proc->procgroup->pgid); +} + +/* int get_exec_pid (void) */ +DEFINE_SYSCALL (sys_get_exec_pid) { return SYSRESULT (proc->exec_pid); } + static syscall_handler_func_t handler_table[] = { [SYS_QUIT] = &sys_quit, [SYS_TEST] = &sys_test, @@ -399,6 +465,10 @@ static syscall_handler_func_t handler_table[] = { [SYS_CLOSE] = &sys_close, [SYS_READ] = &sys_read, [SYS_DESCRIBE] = &sys_describe, + [SYS_MAIL_SEND] = &sys_mail_send, + [SYS_MAIL_RECEIVE] = &sys_mail_receive, + [SYS_GET_PROCGROUP] = &sys_get_procgroup, + [SYS_GET_EXEC_PID] = &sys_get_exec_pid, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libmsl/init/__premain.c b/libmsl/init/__premain.c index 53a3eb2..f0d89c2 100644 --- a/libmsl/init/__premain.c +++ b/libmsl/init/__premain.c @@ -16,8 +16,12 @@ static void clear_bss (void) { void __premain (void) { clear_bss (); + liballoc_init (); + app_main (); + liballoc_deinit (); + quit (); } diff --git a/libmsl/m/system.c b/libmsl/m/system.c index 1618c77..2c009b5 100644 --- a/libmsl/m/system.c +++ b/libmsl/m/system.c @@ -52,3 +52,15 @@ int read (const char* path, size_t off, uint8_t* buffer, size_t size) { int describe (const char* path, struct fs_desc_buffer* desc) { return (int)do_syscall (SYS_DESCRIBE, path, desc); } + +int mail_send (int pgid, void* mesg, size_t mesg_size) { + return (int)do_syscall (SYS_MAIL_SEND, pgid, mesg, mesg_size); +} + +int mail_receive (void* mesg, size_t mesg_size) { + return (int)do_syscall (SYS_MAIL_RECEIVE, mesg, mesg_size); +} + +int get_procgroup (int pid) { return (int)do_syscall (SYS_GET_PROCGROUP, pid); } + +int get_exec_pid (void) { return (int)do_syscall (SYS_GET_EXEC_PID, 0); } diff --git a/libmsl/m/system.h b/libmsl/m/system.h index 4eb2fb9..d2bfa87 100644 --- a/libmsl/m/system.h +++ b/libmsl/m/system.h @@ -65,4 +65,16 @@ int read (const char* path, size_t off, uint8_t* buffer, size_t size); /* describe a file */ int describe (const char* path, struct fs_desc_buffer* desc); +/* send a message to a procgroup's mail */ +int mail_send (int pgid, void* mesg, size_t mesg_size); + +/* receive a message from mail */ +int mail_receive (void* mesg, size_t mesg_size); + +/* get procgroup id of a perticular process */ +int get_procgroup (int pid); + +/* get PID of process, which exec'ed the current process */ +int get_exec_pid (void); + #endif // _LIBMSL_M_SYSTEM_H diff --git a/libprocess/process.c b/libprocess/process.c index b87b3da..591a151 100644 --- a/libprocess/process.c +++ b/libprocess/process.c @@ -13,9 +13,3 @@ int process_spawn (process_func_t func, void* argument_ptr) { uintptr_t top = (uintptr_t)stack + STACK_SIZE; return clone (top, func, argument_ptr); } - -int process_quit (void) { return quit (); } - -void* process_argument (void) { return argument_ptr (); } - -int process_exec (const char* path) { return exec (path); } diff --git a/libprocess/process.h b/libprocess/process.h index f272ee6..647c208 100644 --- a/libprocess/process.h +++ b/libprocess/process.h @@ -12,13 +12,4 @@ typedef void (*process_func_t) (void); /* Spawn a new process within the same procgroup with argument */ int process_spawn (process_func_t func, void* argument_ptr); -/* Quit the current process */ -int process_quit (void); - -/* Get process argument pointer */ -void* process_argument (void); - -/* Run ELF process */ -int process_exec (const char* path); - #endif // _LIBPROCESS_PROCESS_PROCESS_H