Improve context switching and scheduler APIs.
authorcoderain <coderain@sdf.org>
Mon, 18 Jun 2018 05:01:01 +0000 (07:01 +0200)
committercoderain <coderain@sdf.org>
Mon, 18 Jun 2018 05:01:01 +0000 (07:01 +0200)
14 files changed:
drivers/serial/src/main.c
kernel/include/pipe.h
kernel/include/thread.h
kernel/src/exception.c
kernel/src/filesystem.c
kernel/src/interrupt.c
kernel/src/lock.c
kernel/src/pipe.c
kernel/src/process.c
kernel/src/semaphore.c
kernel/src/syscalls.c
kernel/src/thread.c
sdk/defs.h
sdk/pipe.h

index a0a052e83d2f054092bdee2a3049e9870f3563a4..93442ba3e87d6bad0eed325e26d1910ff6bcb552 100644 (file)
@@ -182,7 +182,7 @@ static dword_t serial_read(device_t *device, void *buffer, size_t length, size_t
 
     for (i = 0; i < length; i++)
     {
-        if (current_thread->cancel_io)
+        if (current_thread->terminating)
         {
             ret = ERR_CANCELED;
             break;
@@ -212,7 +212,7 @@ static dword_t serial_write(device_t *device, const void *buffer, size_t length,
 
     for (i = 0; i < length; i++)
     {
-        if (current_thread->cancel_io)
+        if (current_thread->terminating)
         {
             ret = ERR_CANCELED;
             break;
index df7c0b6fde2fc358f847531d481bdf63f79b8d5e..9b09895f461393982e27fac1061893dd29493ab0 100644 (file)
@@ -21,7 +21,9 @@
 #define _PIPE_H_
 
 #include <sync.h>
+#include <object.h>
 #include <sdk/pipe.h>
+#include <thread.h>
 
 #define PIPE_BLOCK_SIZE 1024
 #define MAX_PIPE_BLOCKS 1024
@@ -41,6 +43,7 @@ typedef struct
     object_t header;
     dword_t flags;
     lock_t lock;
+    dword_t bytes_ready;
     list_entry_t fifo;
 } pipe_t;
 
@@ -79,8 +82,9 @@ static inline void init_pipe(pipe_t *pipe, dword_t flags)
     list_init(&pipe->fifo);
 }
 
-dword_t read_pipe(pipe_t *pipe, void *buffer, size_t size, dword_t timeout);
+dword_t read_pipe(pipe_t *pipe, void *buffer, size_t *size, dword_t timeout);
 dword_t write_pipe(pipe_t *pipe, const void *buffer, size_t size);
-void pipe_cleanup(pipe_t *pipe);
+void pipe_cleanup(object_t *obj);
+dword_t pipe_pre_wait(object_t *obj, void *parameter, wait_condition_t *condition);
 
 #endif
index 37e947ba52eee9e57d99d1a4ef4681df697cfc27..902cf1b4b9ab81092e921a3c14a731768e96cdb6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * thread.h
  *
- * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
 
 typedef enum
 {
-    WAIT_NEVER,
     WAIT_ALWAYS,
+    WAIT_GROUP_ANY,
+    WAIT_GROUP_ALL,
     WAIT_UNTIL_EQUAL,
     WAIT_UNTIL_NOT_EQUAL,
     WAIT_UNTIL_LESS,
     WAIT_UNTIL_NOT_LESS,
     WAIT_UNTIL_GREATER,
     WAIT_UNTIL_NOT_GREATER
-} wait_condition_t;
+} wait_condition_type_t;
 
 typedef enum
 {
@@ -54,6 +55,30 @@ typedef enum
     WAIT_CANCELED
 } wait_result_t;
 
+typedef struct wait_condition
+{
+    wait_condition_type_t type;
+
+    union
+    {
+        struct
+        {
+            dword_t *pointer;
+            dword_t value;
+        };
+
+        struct wait_condition *conditions[VARIABLE_SIZE];
+    };
+} wait_condition_t;
+
+typedef struct
+{
+    wait_condition_t *root;
+    timeout_t timeout;
+    qword_t timestamp;
+    wait_result_t result;
+} wait_t;
+
 #ifndef PROCESS_TYPEDEF
 #define PROCESS_TYPEDEF
 typedef struct process process_t;
@@ -78,17 +103,12 @@ struct thread
     void *kernel_stack;
     uintptr_t kernel_esp;
 
-    lock_t syscall_lock;
-    registers_t *syscall_regs;
-    bool_t cancel_io;
+    int in_kernel;
+    registers_t *last_context;
+    bool_t terminating;
     processor_mode_t previous_mode;
 
-    wait_condition_t wait_condition;
-    wait_result_t wait_result;
-    qword_t wait_timestamp;
-    dword_t wait_timeout;
-    dword_t *wait_pointer;
-    dword_t wait_value;
+    wait_t *wait;
 
     exception_handler_t kernel_handler;
     exception_info_t kernel_exception_info;
@@ -107,7 +127,7 @@ thread_t *get_current_thread();
 dword_t create_thread_internal(process_t *proc, thread_state_t *initial_state, dword_t flags, priority_t priority, void *kernel_stack, thread_t **new_thread);
 dword_t terminate_thread_internal(thread_t *thread, dword_t return_value);
 void scheduler(registers_t *regs);
-wait_result_t scheduler_wait(wait_condition_t condition, dword_t timeout, uintptr_t *pointer, uintptr_t value);
+wait_result_t scheduler_wait(wait_condition_t *condition, dword_t timeout);
 dword_t create_system_thread(thread_procedure_t routine, dword_t flags, priority_t priority, dword_t stack_size, void *param, thread_t **new_thread);
 void thread_lazy_fpu(void);
 void thread_cleanup(object_t *thread);
index 185099c14e0967bf89eaf65938854bb436ae1397..242333bfab2224f59412e6016bef703d7b2e5ccf 100644 (file)
@@ -221,7 +221,7 @@ void set_exception_handler(registers_t *regs, processor_mode_t mode, exception_h
 
 sysret_t syscall_save_exception_handler(exception_handler_t *old_handler)
 {
-    set_exception_handler(old_handler, USER_MODE, get_current_thread()->syscall_regs);
+    set_exception_handler(old_handler, USER_MODE, get_current_thread()->last_context);
     return 0;
 }
 
index 328cb8356e9c81393f2da2ff9e5c91f5fca8453e..620cd3891fa3d765fefbb1b2a7fb2baafd9a7f12 100644 (file)
@@ -110,7 +110,7 @@ void file_instance_cleanup(file_instance_t *instance)
         list_remove(&instance->watch->list);
         release_lock(&file->volume->event_watch_list_lock);
 
-        pipe_cleanup(&instance->watch->pipe);
+        pipe_cleanup(&instance->watch->pipe.header);
 
         free(instance->watch);
         instance->watch = NULL;
@@ -469,6 +469,12 @@ sysret_t syscall_delete_file(const char *path)
     mounted_volume_t *vol = get_volume_from_path(normalized_path);
     if (vol == NULL) return ERR_NOTFOUND;
 
+    if (vol->flags & MOUNT_FLAG_READONLY)
+    {
+        ret = ERR_WRITEPROT;
+        goto cleanup;
+    }
+
     acquire_resource_exclusive(&vol->resource);
 
     file_t *file = NULL;
@@ -685,7 +691,7 @@ sysret_t syscall_write_file(handle_t handle, const void *buffer, qword_t offset,
         goto cleanup;
     }
 
-    if (!(file->global->volume->flags & MOUNT_FLAG_READONLY))
+    if (file->global->volume->flags & MOUNT_FLAG_READONLY)
     {
         ret = ERR_WRITEPROT;
         goto cleanup;
@@ -737,7 +743,7 @@ sysret_t syscall_wait_directory_event(handle_t handle, dword_t event_mask, file_
     }
 
     directory->watch->event_mask = event_mask;
-    dword_t ret = read_pipe(&directory->watch->pipe, buffer, size, timeout);
+    dword_t ret = read_pipe(&directory->watch->pipe, buffer, &size, timeout);
 
     dereference(&directory->header);
     return ret;
index fcbcfe99a546ff480695fe8ae5edf58918910c17..c4ebd7a03f27f09c1db56377883557c05db6f1c9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * interrupt.c
  *
- * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -20,6 +20,7 @@
 #include <interrupt.h>
 #include <segments.h>
 #include <sync.h>
+#include <thread.h>
 
 static byte_t isr_stubs[IDT_NUM_INTERRUPTS * ISR_STUB_SIZE];
 static idt_entry_t idt[IDT_NUM_INTERRUPTS];
@@ -38,9 +39,35 @@ static void idt_main_handler(byte_t interrupt_num, registers_t regs)
     regs.esp += 16;
     if (handlers[interrupt_num].procedure == NULL) return;
 
+    thread_t *thread = get_current_thread();
+
+    if (thread)
+    {
+        if (thread->in_kernel == 0) thread->last_context = &regs;
+        thread->in_kernel++;
+    }
+
     if (handlers[interrupt_num].interrupts) enable_ints();
     handlers[interrupt_num].procedure(&regs, interrupt_num);
-    if (handlers[interrupt_num].interrupts) disable_ints();
+
+    if (thread)
+    {
+        ASSERT(thread->in_kernel > 0);
+        if (--thread->in_kernel == 0)
+        {
+            thread->last_context = NULL;
+
+            if (thread->terminated || (thread->frozen > 0))
+            {
+                enable_ints();
+                syscall_yield_quantum();
+            }
+
+            ASSERT(!thread->terminated && (thread->frozen <= 0));
+        }
+    }
+
+    disable_ints();
 }
 
 dword_t set_int_handler(byte_t interrupt_num, isr_proc_t proc, bool_t interrupts, bool_t usermode)
index 524f41cbb290f883bf3c0af230c8aefb2c9d34af..3cf37f0b098bf9f6b1efb2d77f302475aa219bf3 100644 (file)
@@ -47,6 +47,7 @@ void leave_critical(critical_t *critical)
 void lock_acquire(lock_t *lock)
 {
     uintptr_t new_holder = scheduler_enabled ? (uintptr_t)get_current_thread() : UNKNOWN_HOLDER;
+    wait_condition_t condition = { .type = WAIT_UNTIL_EQUAL, .pointer = &lock->holder, .value = 0 };
 
     for (;;)
     {
@@ -59,12 +60,21 @@ void lock_acquire(lock_t *lock)
             return;
         }
 
-        if (scheduler_enabled) scheduler_wait(WAIT_UNTIL_EQUAL, NO_TIMEOUT, &lock->holder, NO_HOLDER);
+        if (scheduler_enabled) scheduler_wait(&condition, NO_TIMEOUT);
     }
 }
 
 static inline void lock_acquire_smart_by(lock_t *lock, uintptr_t new_holder)
 {
+    wait_condition_t condition1 = { .type = WAIT_UNTIL_EQUAL, .pointer = &lock->holder, .value = 0 };
+    wait_condition_t condition2 = { .type = WAIT_UNTIL_EQUAL, .pointer = &lock->holder, .value = new_holder };
+
+    wait_condition_t *condition = __builtin_alloca(sizeof(wait_condition_t) + 3 * sizeof(wait_condition_t*));
+    condition->type = WAIT_GROUP_ANY;
+    condition->conditions[0] = &condition1;
+    condition->conditions[1] = &condition2;
+    condition->conditions[2] = NULL;
+
     for (;;)
     {
         uintptr_t old_holder = NO_HOLDER;
@@ -76,7 +86,7 @@ static inline void lock_acquire_smart_by(lock_t *lock, uintptr_t new_holder)
             return;
         }
 
-        if (scheduler_enabled) scheduler_wait(WAIT_UNTIL_NOT_EQUAL, NO_TIMEOUT, &lock->holder, old_holder);
+        if (scheduler_enabled) scheduler_wait(condition, NO_TIMEOUT);
     }
 }
 
index aebc1f585e782c41ee7136e8bcc9d7f3eed38cc5..a8b6e6af30c74392a11bf4916e5d7e2a0762a327 100644 (file)
@@ -44,9 +44,10 @@ static dword_t create_pipe_internal(pipe_t **_pipe, dword_t flags)
     return ERR_SUCCESS;
 }
 
-dword_t read_pipe(pipe_t *pipe, void *buffer, size_t size, dword_t timeout)
+dword_t read_pipe(pipe_t *pipe, void *buffer, size_t *size, dword_t timeout)
 {
     dword_t ret = ERR_SUCCESS;
+    size_t requested_size = *size;
     acquire_lock(&pipe->lock);
 
     if (pipe->flags & PIPE_MESSAGE)
@@ -54,13 +55,16 @@ dword_t read_pipe(pipe_t *pipe, void *buffer, size_t size, dword_t timeout)
         if (pipe->fifo.next == &pipe->fifo)
         {
             release_lock(&pipe->lock);
-            wait_result_t status = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, (dword_t*)&pipe->fifo.next, 0);
+            wait_condition_t condition = { .type = WAIT_UNTIL_NOT_EQUAL, .pointer = (dword_t*)&pipe->fifo.next, .value = 0 };
+            wait_result_t status = scheduler_wait(&condition, timeout);
             if (status != ERR_SUCCESS) return (status == WAIT_TIMED_OUT) ? ERR_TIMEOUT : ERR_CANCELED;
             acquire_lock(&pipe->lock);
         }
 
         pipe_message_entry_t *entry = CONTAINER_OF(pipe->fifo.next, pipe_message_entry_t, link);
-        if (size < entry->size)
+        *size = entry->size;
+
+        if (requested_size < entry->size)
         {
             ret = ERR_SMALLBUF;
             goto cleanup;
@@ -74,23 +78,24 @@ dword_t read_pipe(pipe_t *pipe, void *buffer, size_t size, dword_t timeout)
     else
     {
         byte_t *data = (byte_t*)buffer;
-        dword_t count = 0;
+        *size = 0;
 
-        while (count < size)
+        while (*size < requested_size)
         {
             if (pipe->fifo.next == &pipe->fifo)
             {
                 release_lock(&pipe->lock);
-                wait_result_t status = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, (dword_t*)&pipe->fifo.next, 0);
+                wait_condition_t condition = { .type = WAIT_UNTIL_NOT_EQUAL, .pointer = (dword_t*)&pipe->fifo.next, .value = 0 };
+                wait_result_t status = scheduler_wait(&condition, timeout);
                 if (status != ERR_SUCCESS) return (status == WAIT_TIMED_OUT) ? ERR_TIMEOUT : ERR_CANCELED;
                 acquire_lock(&pipe->lock);
             }
 
             pipe_fifo_entry_t *entry = CONTAINER_OF(pipe->fifo.next, pipe_fifo_entry_t, link);
 
-            while ((count < size) && ((entry->start != entry->end) || entry->full))
+            while ((*size < requested_size) && ((entry->start != entry->end) || entry->full))
             {
-                data[count++] = entry->data[entry->start++];
+                data[(*size)++] = entry->data[entry->start++];
                 entry->start %= PIPE_BLOCK_SIZE;
                 entry->full = FALSE;
             }
@@ -103,6 +108,8 @@ dword_t read_pipe(pipe_t *pipe, void *buffer, size_t size, dword_t timeout)
         }
     }
 
+    pipe->bytes_ready -= *size;
+
 cleanup:
     release_lock(&pipe->lock);
     return ret;
@@ -127,6 +134,7 @@ dword_t write_pipe(pipe_t *pipe, const void *buffer, size_t size)
         entry->size = size;
         memcpy(entry->data, buffer, size);
         list_append(&pipe->fifo, &entry->link);
+        count = size;
     }
     else
     {
@@ -159,13 +167,17 @@ dword_t write_pipe(pipe_t *pipe, const void *buffer, size_t size)
         }
     }
 
+
+    pipe->bytes_ready += count;
+
 cleanup:
     release_lock(&pipe->lock);
     return ret;
 }
 
-void pipe_cleanup(pipe_t *pipe)
+void pipe_cleanup(object_t *obj)
 {
+    pipe_t *pipe = (pipe_t*)obj;
     while (pipe->fifo.next != &pipe->fifo)
     {
         pipe_fifo_entry_t *entry = CONTAINER_OF(pipe->fifo.next, pipe_fifo_entry_t, link);
@@ -351,7 +363,8 @@ sysret_t syscall_listen_pipeline(handle_t handle, dword_t timeout, pipe_connecti
     pipeline->status = PIPELINE_ACCEPTING;
     release_lock(&pipeline->lock);
 
-    wait_result_t result = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, &pipeline->status, PIPELINE_ACCEPTING);
+    wait_condition_t condition = { .type = WAIT_UNTIL_NOT_EQUAL, .pointer = &pipeline->status, .value = PIPELINE_ACCEPTING };
+    wait_result_t result = scheduler_wait(&condition, timeout);
     acquire_lock(&pipeline->lock);
 
     if (pipeline->status != PIPELINE_CONNECTING)
@@ -476,35 +489,53 @@ cleanup:
     return ret;
 }
 
-sysret_t syscall_read_pipe(handle_t handle, void *buffer, size_t size, dword_t timeout)
+sysret_t syscall_read_pipe(handle_t handle, void *buffer, size_t *size, dword_t timeout)
 {
     pipe_t *pipe;
     void *safe_buffer = NULL;
+    size_t safe_size = 0;
 
     if (get_previous_mode() == USER_MODE)
     {
-        if (!check_usermode(buffer, size)) return ERR_BADPTR;
+        if (!check_usermode(size, sizeof(size_t))) return ERR_BADPTR;
 
-        safe_buffer = malloc(size);
+        EH_TRY safe_size = *size;
+        EH_CATCH EH_ESCAPE(return ERR_BADPTR);
+        EH_DONE;
+
+        if (!check_usermode(buffer, safe_size)) return ERR_BADPTR;
+        safe_buffer = malloc(safe_size);
         if (safe_buffer == NULL) return ERR_NOMEMORY;
     }
     else
     {
         safe_buffer = buffer;
+        safe_size = *size;
     }
 
     if (!reference_by_handle(handle, OBJECT_PIPE, (object_t**)&pipe)) return ERR_INVALID;
-    dword_t ret = read_pipe(pipe, (byte_t*)safe_buffer, size, timeout);
+    dword_t ret = read_pipe(pipe, (byte_t*)safe_buffer, &safe_size, timeout);
     dereference(&pipe->header);
 
     if (get_previous_mode() == USER_MODE)
     {
-        EH_TRY memcpy(buffer, safe_buffer, size);
-        EH_CATCH ret = ERR_BADPTR;
+        EH_TRY
+        {
+            memcpy(buffer, safe_buffer, safe_size);
+            *size = safe_size;
+        }
+        EH_CATCH
+        {
+            ret = ERR_BADPTR;
+        }
         EH_DONE;
 
         free(safe_buffer);
     }
+    else
+    {
+        *size = safe_size;
+    }
 
     return ret;
 }
@@ -521,7 +552,10 @@ sysret_t syscall_write_pipe(handle_t handle, void *buffer, size_t size)
         safe_buffer = (byte_t*)malloc(size);
         if (safe_buffer == NULL) return ERR_NOMEMORY;
 
-        EH_TRY memcpy(safe_buffer, buffer, size);
+        EH_TRY
+        {
+            memcpy(safe_buffer, buffer, size);
+        }
         EH_CATCH
         {
             free(safe_buffer);
index 097e8a845c729b38033e4a3c1541f39a43c05264..50715015ef5a2291a92151749e87efc01b5126bf 100644 (file)
@@ -328,7 +328,7 @@ sysret_t syscall_create_process(const char *path, dword_t flags, process_params_
     }
     else
     {
-        initial_state.regs = *get_current_thread()->syscall_regs;
+        initial_state.regs = *get_current_thread()->last_context;
         fpu_save(initial_state.fpu_state);
         initial_state.regs.eax = CLONE_MAGIC;
     }
@@ -711,7 +711,8 @@ sysret_t syscall_wait_process(handle_t handle, dword_t timeout)
         if (!reference_by_handle(handle, OBJECT_PROCESS, (object_t**)&proc)) return ERR_INVALID;
     }
 
-    ret = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, &proc->terminated, 0);
+    wait_condition_t condition = { .type = WAIT_UNTIL_NOT_EQUAL, .pointer = &proc->terminated, .value = 0 };
+    ret = scheduler_wait(&condition, timeout);
 
     dereference(&proc->header);
     return ret;
index 30bf9f46b233d2ef8104da99b17b52927c270c81..7c369764f0540b980b6d0f74fbf3571438ef7338 100644 (file)
@@ -110,10 +110,11 @@ dword_t wait_semaphore(semaphore_t *semaphore, dword_t count, dword_t timeout)
 
     if (semaphore->count < count)
     {
-        dword_t ret = scheduler_wait(WAIT_UNTIL_NOT_LESS, timeout, &semaphore->count, count);
+        wait_condition_t condition = { .type = WAIT_UNTIL_NOT_LESS, .pointer = &semaphore->count, .value = count };
+        wait_result_t result = scheduler_wait(&condition, timeout);
 
-        if (ret == WAIT_TIMED_OUT) return ERR_TIMEOUT;
-        else if (ret == WAIT_CANCELED) return ERR_CANCELED;
+        if (result == WAIT_TIMED_OUT) return ERR_TIMEOUT;
+        else if (result == WAIT_CANCELED) return ERR_CANCELED;
     }
 
     semaphore->count -= count;
index 97cfd328761c041bb5698cdba4da1e405acac804..5753200eb0a2a0a2c30e76e74dc900744a4d3076 100644 (file)
@@ -36,7 +36,6 @@ extern sysret_t syscall_function(const void*, dword_t*, dword_t);
 static void system_service_handler(registers_t *regs, byte_t int_num)
 {
     dword_t parameters[MAX_PARAMETERS];
-    thread_t *thread = get_current_thread();
 
     if (regs->eax >= SERVICE_COUNT)
     {
@@ -44,15 +43,12 @@ static void system_service_handler(registers_t *regs, byte_t int_num)
         return;
     }
 
-    acquire_lock(&thread->syscall_lock);
-    thread->syscall_regs = regs;
-
     if (get_previous_mode() == USER_MODE)
     {
         if (!check_usermode((dword_t*)regs->edx, sizeof(parameters)))
         {
             regs->eax = ERR_BADPTR;
-            goto cleanup;
+            return;
         }
 
         EH_TRY
@@ -62,7 +58,7 @@ static void system_service_handler(registers_t *regs, byte_t int_num)
         EH_CATCH
         {
             regs->eax = ERR_BADPTR;
-            EH_ESCAPE(goto cleanup);
+            EH_ESCAPE(return);
         }
         EH_DONE;
     }
@@ -74,12 +70,6 @@ static void system_service_handler(registers_t *regs, byte_t int_num)
     sysret_t result = syscall_function(service_table[regs->eax], parameters, sizeof(parameters));
     regs->eax = (dword_t)result;
     regs->edx = (dword_t)(result >> 32);
-
-cleanup:
-    thread->syscall_regs = NULL;
-    release_lock(&thread->syscall_lock);
-    if (thread->cancel_io) while (TRUE) syscall_yield_quantum();
-    else if (thread->frozen) syscall_yield_quantum();
 }
 
 processor_mode_t get_previous_mode()
index 8d2ee47d855d28a6b726654ac82ebbe174718d61..3ed51bbb39879b4ed51e0d255212f76916a27de9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * thread.c
  *
- * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -56,77 +56,57 @@ static dword_t alloc_tid()
     return tid;
 }
 
-static inline bool_t test_condition(wait_condition_t condition, dword_t *pointer, dword_t value)
+static inline bool_t test_condition(wait_condition_t *condition)
 {
-    bool_t satisfied;
+    wait_condition_t **ptr;
 
-    switch (condition)
+    switch (condition->type)
     {
-    case WAIT_NEVER:
-        satisfied = TRUE;
-        break;
-
+    case WAIT_GROUP_ANY:
+        for (ptr = condition->conditions; *ptr; ptr++) if (test_condition(*ptr)) return TRUE;
+        return FALSE;
+    case WAIT_GROUP_ALL:
+        for (ptr = condition->conditions; *ptr; ptr++) if (!test_condition(*ptr)) return FALSE;
+        return TRUE;
     case WAIT_ALWAYS:
-        satisfied = FALSE;
-        break;
-
+        return FALSE;
     case WAIT_UNTIL_EQUAL:
-        satisfied = (*pointer == value);
-        break;
-
+        return *condition->pointer == condition->value;
     case WAIT_UNTIL_NOT_EQUAL:
-        satisfied = (*pointer != value);
-        break;
-
+        return (*condition->pointer != condition->value);
     case WAIT_UNTIL_LESS:
-        satisfied = (*pointer < value);
-        break;
-
+        return (*condition->pointer < condition->value);
     case WAIT_UNTIL_NOT_LESS:
-        satisfied = (*pointer >= value);
-        break;
-
+        return (*condition->pointer >= condition->value);
     case WAIT_UNTIL_GREATER:
-        satisfied = (*pointer > value);
-        break;
-
+        return (*condition->pointer > condition->value);
     case WAIT_UNTIL_NOT_GREATER:
-        satisfied = (*pointer <= value);
-        break;
-
+        return (*condition->pointer <= condition->value);
     default:
         KERNEL_CRASH("Invalid wait condition value");
-        break;
+        return FALSE;
     }
-
-    return satisfied;
 }
 
 static inline bool_t is_thread_ready(thread_t *thread)
 {
     qword_t current_time = syscall_get_milliseconds();
 
-    if (thread->terminated) return FALSE;
-    if (thread->frozen > 0 && !thread->syscall_lock) return FALSE;
+    if (thread->terminating || thread->terminated) return FALSE;
+    if (thread->frozen > 0 && !thread->in_kernel) return FALSE;
+    if (!thread->wait) return TRUE;
 
-    if (test_condition(thread->wait_condition, thread->wait_pointer, thread->wait_value))
+    if (test_condition(thread->wait->root))
     {
-        thread->wait_condition = WAIT_NEVER;
-        thread->wait_result = WAIT_CONDITION_HIT;
+        thread->wait->result = WAIT_CONDITION_HIT;
+        thread->wait = NULL;
         return TRUE;
     }
 
-    if (thread->wait_timeout != 0ULL && (current_time - thread->wait_timestamp) >= (qword_t)thread->wait_timeout)
+    if (thread->wait->timeout != NO_TIMEOUT && (current_time - thread->wait->timestamp) >= (qword_t)thread->wait->timeout)
     {
-        thread->wait_condition = WAIT_NEVER;
-        thread->wait_result = WAIT_TIMED_OUT;
-        return TRUE;
-    }
-
-    if (thread->cancel_io)
-    {
-        thread->wait_condition = WAIT_NEVER;
-        thread->wait_result = WAIT_CANCELED;
+        thread->wait->result = WAIT_TIMED_OUT;
+        thread->wait = NULL;
         return TRUE;
     }
 
@@ -187,14 +167,11 @@ dword_t create_thread_internal(process_t *proc, thread_state_t *initial_state, d
     thread->running_ticks = 0ULL;
     thread->owner_process = proc;
     thread->exit_code = 0;
+    thread->terminating = FALSE;
     thread->terminated = FALSE;
-    thread->cancel_io = FALSE;
-    thread->syscall_lock = 0;
-    thread->wait_condition = WAIT_NEVER;
-    thread->wait_timestamp = 0ULL;
-    thread->wait_timeout = 0;
-    thread->wait_pointer = NULL;
-    thread->wait_value = 0;
+    thread->in_kernel = 0;
+    thread->last_context = NULL;
+    thread->wait = NULL;
     memset(&thread->kernel_handler, 0, sizeof(thread->kernel_handler));
     memset(&thread->user_handler, 0, sizeof(thread->user_handler));
 
@@ -353,39 +330,22 @@ found:
     leave_critical(&critical);
 }
 
-wait_result_t scheduler_wait(wait_condition_t condition, dword_t timeout, uintptr_t *pointer, uintptr_t value)
+wait_result_t scheduler_wait(wait_condition_t *condition, dword_t timeout)
 {
-    if (test_condition(condition, pointer, value)) return WAIT_CONDITION_HIT;
+    if (test_condition(condition)) return WAIT_CONDITION_HIT;
     if (timeout == 0) return WAIT_TIMED_OUT;
 
-    critical_t critical;
-    enter_critical(&critical);
-
-    if (timeout != NO_TIMEOUT)
-    {
-        current_thread->wait_timestamp = syscall_get_milliseconds();
-        current_thread->wait_timeout = timeout;
-    }
-    else
-    {
-        current_thread->wait_timestamp = 0ULL;
-        current_thread->wait_timeout = 0;
-    }
-
-    current_thread->wait_pointer = pointer;
-    current_thread->wait_value = value;
-    current_thread->wait_condition = condition;
-
-    leave_critical(&critical);
+    wait_t wait = { .root = condition, .timeout = timeout,  .timestamp = syscall_get_milliseconds(), .result = WAIT_CANCELED };
+    while (!__sync_bool_compare_and_swap(&current_thread->wait, NULL, &wait)) continue;
     syscall_yield_quantum();
 
-    return current_thread->wait_result;
+    return wait.result;
 }
 
 sysret_t syscall_sleep(qword_t milliseconds)
 {
-    scheduler_wait(WAIT_ALWAYS, milliseconds, NULL, 0);
-    return ERR_SUCCESS;
+    wait_condition_t condition = { .type = WAIT_ALWAYS };
+    return scheduler_wait(&condition, milliseconds) == WAIT_CANCELED ? ERR_CANCELED : ERR_SUCCESS;
 }
 
 sysret_t syscall_yield_quantum()
@@ -528,9 +488,15 @@ found:
 dword_t terminate_thread_internal(thread_t *thread, dword_t exit_code)
 {
     critical_t critical;
-    thread->cancel_io = TRUE;
+    thread->terminating = TRUE;
+
+    if (thread != current_thread)
+    {
+        wait_condition_t cond = { .type = WAIT_UNTIL_EQUAL, .pointer = (dword_t*)&thread->in_kernel, .value = 0 };
+        wait_result_t result = scheduler_wait(&cond, NO_TIMEOUT);
+        if (result == WAIT_CANCELED) return ERR_CANCELED;
+    }
 
-    if (thread != current_thread) acquire_lock(&thread->syscall_lock);
     enter_critical(&critical);
 
     thread->exit_code = exit_code;
@@ -610,7 +576,7 @@ sysret_t syscall_query_thread(handle_t handle, thread_info_t info_type, void *bu
                 }
                 else
                 {
-                    ((thread_state_t*)safe_buffer)->regs = *thread->syscall_regs;
+                    ((thread_state_t*)safe_buffer)->regs = *thread->last_context;
                     fpu_save(((thread_state_t*)safe_buffer)->fpu_state);
                 }
             }
@@ -694,7 +660,7 @@ sysret_t syscall_set_thread(handle_t handle, thread_info_t info_type, const void
             critical_t critical;
             if (current_thread->tid != thread->tid) enter_critical(&critical);
 
-            if (thread->syscall_lock == 0)
+            if (thread->in_kernel == 0)
             {
                 thread->state.regs.eax = new_state->regs.eax;
                 thread->state.regs.ecx = new_state->regs.ecx;
@@ -707,21 +673,20 @@ sysret_t syscall_set_thread(handle_t handle, thread_info_t info_type, const void
                 thread->state.regs.eip = new_state->regs.eip;
                 thread->state.regs.eflags = (thread->state.regs.eflags & ~SAFE_EFLAGS_MASK) | (new_state->regs.eflags & SAFE_EFLAGS_MASK);
             }
-            else if (thread->syscall_regs != NULL)
+            else if (thread->last_context)
             {
-                thread->syscall_regs->eax = new_state->regs.eax;
-                thread->syscall_regs->ecx = new_state->regs.ecx;
-                thread->syscall_regs->edx = new_state->regs.edx;
-                thread->syscall_regs->ebx = new_state->regs.ebx;
-                thread->syscall_regs->esp = new_state->regs.esp;
-                thread->syscall_regs->ebp = new_state->regs.ebp;
-                thread->syscall_regs->esi = new_state->regs.esi;
-                thread->syscall_regs->edi = new_state->regs.edi;
-                thread->syscall_regs->eip = new_state->regs.eip;
-                thread->syscall_regs->eflags = (thread->state.regs.eflags & ~SAFE_EFLAGS_MASK) | (new_state->regs.eflags & SAFE_EFLAGS_MASK);
+                thread->last_context->eax = new_state->regs.eax;
+                thread->last_context->ecx = new_state->regs.ecx;
+                thread->last_context->edx = new_state->regs.edx;
+                thread->last_context->ebx = new_state->regs.ebx;
+                thread->last_context->esp = new_state->regs.esp;
+                thread->last_context->ebp = new_state->regs.ebp;
+                thread->last_context->esi = new_state->regs.esi;
+                thread->last_context->edi = new_state->regs.edi;
+                thread->last_context->eip = new_state->regs.eip;
+                thread->last_context->eflags = (thread->last_context->eflags & ~SAFE_EFLAGS_MASK) | (new_state->regs.eflags & SAFE_EFLAGS_MASK);
             }
 
-
             if (current_thread->tid != thread->tid)
             {
                 memcpy(thread->state.fpu_state, new_state->fpu_state, sizeof(thread->state.fpu_state));
@@ -773,7 +738,8 @@ sysret_t syscall_wait_thread(handle_t handle, dword_t timeout)
         if (!reference_by_handle(handle, OBJECT_THREAD, (object_t**)&thread)) return ERR_INVALID;
     }
 
-    ret = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, &thread->terminated, FALSE);
+    wait_condition_t condition = { .type = WAIT_UNTIL_NOT_EQUAL, .pointer = &thread->terminated, .value = FALSE };
+    ret = scheduler_wait(&condition, timeout);
 
     dereference(&thread->header);
     return ret;
@@ -851,14 +817,11 @@ void thread_init(void)
     main_thread->running_ticks = 0ULL;
     main_thread->owner_process = kernel_process;
     list_append(&kernel_process->threads, &main_thread->in_process_list);
-    main_thread->syscall_lock = 0;
+    main_thread->in_kernel = 1;
+    main_thread->last_context = NULL;
     main_thread->terminated = FALSE;
     main_thread->previous_mode = KERNEL_MODE;
-    main_thread->wait_condition = WAIT_NEVER;
-    main_thread->wait_timestamp = 0ULL;
-    main_thread->wait_timeout = 0;
-    main_thread->wait_pointer = NULL;
-    main_thread->wait_value = 0;
+    main_thread->wait = NULL;
 
     memset(&main_thread->kernel_handler, 0, sizeof(main_thread->kernel_handler));
     memset(&main_thread->user_handler, 0, sizeof(main_thread->user_handler));
index 69584660bdb7d9370f9ceae7e7e30bed819b0db0..4d42a2d943b8a1d8b48e4cd1b400d8c2e5fdb63a 100644 (file)
@@ -77,6 +77,8 @@ typedef uint64_t qword_t;
 /* System call return value */
 typedef qword_t sysret_t;
 
+typedef dword_t timeout_t;
+
 static inline void set_bit(dword_t *bitfield, dword_t bit)
 {
     bitfield[bit >> 5] |= 1 << (bit & 0x1F);
index d3c987405dd42e9957c17f9b1ff99487e30c4a4a..d2ade679d5949b1138f9e61b6b8923bf2fd07198 100644 (file)
@@ -34,11 +34,11 @@ typedef struct
     handle_t response_pipe;
 } pipe_connection_t;
 
-sysret_t syscall_create_pipeline(const char *name, dword_t flags,access_flags_t access,  handle_t *handle);
+sysret_t syscall_create_pipeline(const char *name, dword_t flags, access_flags_t access,  handle_t *handle);
 sysret_t syscall_open_pipeline(const char *name, access_flags_t access, handle_t *handle);
 sysret_t syscall_listen_pipeline(handle_t handle, dword_t timeout, pipe_connection_t *connection);
 sysret_t syscall_connect_pipeline(handle_t handle, access_flags_t access, pipe_connection_t *connection);
-sysret_t syscall_read_pipe(handle_t handle, void *buffer, dword_t size, dword_t timeout);
+sysret_t syscall_read_pipe(handle_t handle, void *buffer, dword_t *size, dword_t timeout);
 sysret_t syscall_write_pipe(handle_t handle, void *buffer, dword_t size);
 
 #endif