Improve pipes. Implement pipelines. Use pipes when watching directory changes.
authorcoderain <coderain@sdf.org>
Sun, 24 Dec 2017 06:29:18 +0000 (07:29 +0100)
committercoderain <coderain@sdf.org>
Sun, 24 Dec 2017 06:29:18 +0000 (07:29 +0100)
17 files changed:
kernel/include/filesystem.h
kernel/include/object.h
kernel/include/pipe.h
kernel/src/filesystem.c
kernel/src/memory/memory.c
kernel/src/object.c
kernel/src/pipe.c
kernel/src/process.c
kernel/src/sync.c
kernel/src/syscalls.c
kernel/src/thread.c
kernel/src/user.c
library/src/wrappers.c
sdk/object.h
sdk/pipe.h [new file with mode: 0644]
sdk/syscalls.h
sdk/user.h

index 74f24bb32ea7b3c9f8ebb7cafb242e28f3115747..3b50aeb1cfd6faddabee60a8d2989096bfd7a4dd 100644 (file)
@@ -26,8 +26,7 @@
 #include <clock.h>
 #include <sync.h>
 #include <sdk/filesystem.h>
-
-#define EVENT_QUEUE_CAPACITY 256
+#include <pipe.h>
 
 typedef struct mounted_volume mounted_volume_t;
 typedef struct file file_t;
@@ -65,17 +64,9 @@ typedef struct
 typedef struct
 {
     list_entry_t list;
-    file_event_t event;
-} event_queue_entry_t;
-
-typedef struct
-{
-    list_entry_t list;
-    lock_t lock;
-    file_instance_t *directory; /* weak reference */
+    pipe_t pipe;
     dword_t event_mask;
-    semaphore_t event_semaphore;
-    list_entry_t event_queue;
+    file_instance_t *directory; /* weak reference */
 } event_watch_entry_t;
 
 struct file
index af5f231062fca17c055e3ee4a7d6408ffcae398a..454b6c68c519c7c55cae8e23271d9dc6cb0e491b 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef _OBJECT_H_
 #define _OBJECT_H_
 
+#include <common.h>
 #include <sdk/object.h>
 #include <sdk/list.h>
 
@@ -35,7 +36,8 @@ typedef struct
     list_entry_t by_name_list;
     list_entry_t by_type_list;
     char *name;
-    qword_t ref_count, open_count;
+    qword_t ref_count;
+    dword_t open_count;
     object_type_t type;
     access_control_policy_t acp;
     list_entry_t acl;
@@ -43,6 +45,12 @@ typedef struct
 
 typedef void (*object_cleanup_proc_t)(object_t *obj);
 
+static inline void init_object(object_t *object, const char *name, object_type_t type)
+{
+    object->name = name ? strdup(name) : NULL;
+    object->type = type;
+}
+
 dword_t create_object(object_t *object);
 void reference(object_t *object);
 void dereference(object_t *object);
index 240116069da620c211dd408202e5cbf37ed9ed74..df7c0b6fde2fc358f847531d481bdf63f79b8d5e 100644 (file)
 #ifndef _PIPE_H_
 #define _PIPE_H_
 
-#include <common.h>
-#include <object.h>
 #include <sync.h>
+#include <sdk/pipe.h>
 
-#define PIPE_BLOCK_SIZE 256
+#define PIPE_BLOCK_SIZE 1024
+#define MAX_PIPE_BLOCKS 1024
+
+#define PIPE_MESSAGE (1 << 0)
+
+enum
+{
+    PIPELINE_IDLE,
+    PIPELINE_ACCEPTING,
+    PIPELINE_CONNECTING,
+    PIPELINE_FAILED,
+};
 
 typedef struct
 {
-    list_entry_t list;
+    object_t header;
+    dword_t flags;
+    lock_t lock;
+    list_entry_t fifo;
+} pipe_t;
+
+typedef struct
+{
+    list_entry_t link;
     dword_t start, end;
     bool_t full;
     byte_t data[PIPE_BLOCK_SIZE];
 } pipe_fifo_entry_t;
 
+typedef struct
+{
+    list_entry_t link;
+    size_t size;
+    byte_t data[VARIABLE_SIZE];
+} pipe_message_entry_t;
+
 typedef struct
 {
     object_t header;
+    dword_t flags;
     lock_t lock;
-    list_entry_t fifo;
-} pipe_t;
+    uintptr_t status;
+    dword_t server_pid;
+    dword_t client_pid;
+    pipe_t *request_pipe;
+    pipe_t *response_pipe;
+    dword_t last_error;
+} pipeline_t;
+
+static inline void init_pipe(pipe_t *pipe, dword_t flags)
+{
+    pipe->flags = flags;
+    pipe->lock = 0;
+    list_init(&pipe->fifo);
+}
 
-sysret_t syscall_create_pipe(const char *name, handle_t *handle);
-sysret_t syscall_open_pipe(const char *name, handle_t *handle);
-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);
+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);
 
 #endif
index c1cc4906e16187b118e185a08f03ea4be6a3a3be..328cb8356e9c81393f2da2ff9e5c91f5fca8453e 100644 (file)
@@ -75,21 +75,11 @@ void report_filesystem_event(const char *path, dword_t type)
         if (strncmp(path, watch->directory->global->path, prefix_length) == 0
             && path[prefix_length] == PATH_DELIMITER_CHAR)
         {
-            event_queue_entry_t *entry = (event_queue_entry_t*)malloc(sizeof(event_queue_entry_t) + path_length + 1);
-            entry->event.type = type;
-            strcpy(entry->event.filename, path);
+            file_event_t *file_event = __builtin_alloca(sizeof(file_event_t) + path_length);
+            file_event->type = type;
+            strcpy(file_event->filename, path);
 
-            acquire_lock(&watch->lock);
-            list_append(&watch->event_queue, &entry->list);
-            release_lock(&watch->lock);
-
-            if (release_semaphore(&watch->event_semaphore, 1) == ERR_INVALID)
-            {
-                acquire_lock(&watch->lock);
-                list_remove(&entry->list);
-                release_lock(&watch->lock);
-                free(entry);
-            }
+            write_pipe(&watch->pipe, &file_event, sizeof(file_event) + path_length + 1);
         }
 
         dereference(&watch->directory->header);
@@ -120,14 +110,7 @@ void file_instance_cleanup(file_instance_t *instance)
         list_remove(&instance->watch->list);
         release_lock(&file->volume->event_watch_list_lock);
 
-        ASSERT(!instance->watch->lock);
-
-        while (instance->watch->event_queue.next != &instance->watch->event_queue)
-        {
-            event_queue_entry_t *entry = CONTAINER_OF(instance->watch->event_queue.next, event_queue_entry_t, list);
-            list_remove(&entry->list);
-            free(entry);
-        }
+        pipe_cleanup(&instance->watch->pipe);
 
         free(instance->watch);
         instance->watch = NULL;
@@ -360,8 +343,7 @@ dword_t open_file_internal(const char *path, file_instance_t **file_instance, dw
         file = (file_t*)malloc(sizeof(file_t));
         if (file == NULL) return ERR_NOMEMORY;
 
-        file->header.name = strdup(normalized_path);
-        file->header.type = OBJECT_FILE;
+        init_object(&file->header, normalized_path, OBJECT_FILE);
         file->volume = vol;
 
         file->path = &file->header.name[strlen(vol->mountpoint)];
@@ -394,8 +376,7 @@ dword_t open_file_internal(const char *path, file_instance_t **file_instance, dw
         return ERR_NOMEMORY;
     }
 
-    instance->header.name = NULL;
-    instance->header.type = OBJECT_FILE_INSTANCE;
+    init_object(&instance->header, NULL, OBJECT_FILE_INSTANCE);
     instance->global = file;
     instance->mode = mode;
 
@@ -617,15 +598,18 @@ sysret_t syscall_list_directory(handle_t handle, char *filename, bool_t continue
     dword_t ret = directory->global->volume->driver->list_dir(directory, safe_filename, continue_scan);
     release_resource(&directory->global->volume->resource);
 
-    if (get_previous_mode() != USER_MODE || check_usermode(filename, strlen(safe_filename) + 1))
-    {
-        EH_TRY strcpy(filename, safe_filename);
-        EH_CATCH ret = ERR_BADPTR;
-        EH_DONE;
-    }
-    else
+    if (ret == ERR_SUCCESS)
     {
-        ret = ERR_BADPTR;
+        if (get_previous_mode() != USER_MODE || check_usermode(filename, strlen(safe_filename) + 1))
+        {
+            EH_TRY strcpy(filename, safe_filename);
+            EH_CATCH ret = ERR_BADPTR;
+            EH_DONE;
+        }
+        else
+        {
+            ret = ERR_BADPTR;
+        }
     }
 
     return ret;
@@ -737,8 +721,7 @@ sysret_t syscall_wait_directory_event(handle_t handle, dword_t event_mask, file_
     {
         event_watch_entry_t *watch = (event_watch_entry_t*)malloc(sizeof(event_watch_entry_t));
         watch->directory = directory;
-        init_semaphore(&watch->event_semaphore, 0, EVENT_QUEUE_CAPACITY);
-        list_init(&watch->event_queue);
+        init_pipe(&watch->pipe, PIPE_MESSAGE);
 
         mounted_volume_t *volume = directory->global->volume;
         acquire_lock(&volume->event_watch_list_lock);
@@ -754,38 +737,8 @@ 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 = wait_semaphore(&directory->watch->event_semaphore, 1, timeout);
-    if (ret != ERR_SUCCESS)
-    {
-        dereference(&directory->header);
-        return ret;
-    }
-
-    acquire_lock(&directory->watch->lock);
-
-    event_queue_entry_t *entry = CONTAINER_OF(directory->watch->event_queue.next, event_queue_entry_t, list);
-    dword_t event_size = sizeof(entry->event) + strlen(entry->event.filename) + 1;
-
-    if (size >= event_size)
-    {
-        EH_TRY memcpy(buffer, &entry->event, event_size);
-        EH_CATCH ret = ERR_BADPTR;
-        EH_DONE;
-
-        if (ret == ERR_SUCCESS)
-        {
-            list_remove(&entry->list);
-            free(entry);
-        }
-    }
-    else
-    {
-        ret = ERR_SMALLBUF;
-    }
-
-    if (ret != ERR_SUCCESS) release_semaphore(&directory->watch->event_semaphore, 1);
-    release_lock(&directory->watch->lock);
     dereference(&directory->header);
     return ret;
 }
index f1f0da1ad65173004fd4c162bfec09bf6f384804..03458e3e1e367beb235d5a8788ac584428fedbad 100644 (file)
@@ -1745,9 +1745,7 @@ sysret_t syscall_create_memory_section(const char *name, handle_t file, size_t m
     section->size = max_size;
     section->file = file != INVALID_HANDLE ? file_instance : NULL;
 
-    section->header.name = strdup(safe_name);
-    section->header.type = OBJECT_MEMORY;
-
+    init_object(&section->header, safe_name, OBJECT_MEMORY);
     ret = create_object(&section->header);
     if (ret != ERR_SUCCESS)
     {
index d025c81d3bf4070cb53e0d7022d32fddf8126325..f43c055641c4609cb36ea68f9aa7b26306a1b43c 100644 (file)
 
 extern void file_cleanup(object_t*);
 extern void file_instance_cleanup(object_t*);
-extern void pipe_cleanup(object_t*);
 
 static lock_t obj_lock = 0;
 static DECLARE_LIST(anonymous_objects);
 static DECLARE_LIST_ARRAY(named_objects, 256);
-static DECLARE_LIST_ARRAY(objects_by_type, 8);
+static DECLARE_LIST_ARRAY(objects_by_type, 9);
 static object_cleanup_proc_t cleanup_procedures[OBJECT_TYPE_MAX] =
 {
     file_cleanup,
     file_instance_cleanup,
-    pipe_cleanup,
+    NULL,
+    (object_cleanup_proc_t)pipe_cleanup,
     process_cleanup,
     thread_cleanup,
     memory_cleanup,
@@ -260,7 +260,7 @@ void close_object_internal(object_t *obj)
     acquire_lock(&obj_lock);
 
     obj->open_count--;
-    dword_t ref_count = --obj->ref_count;
+    qword_t ref_count = --obj->ref_count;
 
     if (!ref_count)
     {
index b085ba85354710d5e5d54e4473fc3cfc705375d6..aebc1f585e782c41ee7136e8bcc9d7f3eed38cc5 100644 (file)
 #include <pipe.h>
 #include <exception.h>
 #include <timer.h>
+#include <process.h>
 #include <thread.h>
 #include <syscalls.h>
 #include <heap.h>
 
-sysret_t syscall_create_pipe(const char *name, handle_t *handle)
+static dword_t create_pipe_internal(pipe_t **_pipe, dword_t flags)
+{
+    pipe_t *pipe = (pipe_t*)malloc(sizeof(pipe_t));
+    if (pipe == NULL) return ERR_NOMEMORY;
+
+    init_object(&pipe->header, NULL, OBJECT_PIPE);
+    init_pipe(pipe, flags);
+
+    dword_t ret = create_object(&pipe->header);
+    if (ret != ERR_SUCCESS)
+    {
+        free(pipe);
+        return ret;
+    }
+
+    *_pipe = pipe;
+    return ERR_SUCCESS;
+}
+
+dword_t read_pipe(pipe_t *pipe, void *buffer, size_t size, dword_t timeout)
+{
+    dword_t ret = ERR_SUCCESS;
+    acquire_lock(&pipe->lock);
+
+    if (pipe->flags & PIPE_MESSAGE)
+    {
+        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);
+            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)
+        {
+            ret = ERR_SMALLBUF;
+            goto cleanup;
+        }
+
+        memcpy(buffer, entry->data, entry->size);
+
+        list_remove(&entry->link);
+        heap_free(&evictable_heap, entry);
+    }
+    else
+    {
+        byte_t *data = (byte_t*)buffer;
+        dword_t count = 0;
+
+        while (count < 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);
+                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))
+            {
+                data[count++] = entry->data[entry->start++];
+                entry->start %= PIPE_BLOCK_SIZE;
+                entry->full = FALSE;
+            }
+
+            if ((entry->start == entry->end) && !entry->full)
+            {
+                list_remove(&entry->link);
+                heap_free(&evictable_heap, entry);
+            }
+        }
+    }
+
+cleanup:
+    release_lock(&pipe->lock);
+    return ret;
+}
+
+dword_t write_pipe(pipe_t *pipe, const void *buffer, size_t size)
+{
+    dword_t ret = ERR_SUCCESS;
+    dword_t count = 0;
+
+    acquire_lock(&pipe->lock);
+
+    if (pipe->flags & PIPE_MESSAGE)
+    {
+        pipe_message_entry_t *entry = heap_alloc(&evictable_heap, sizeof(pipe_message_entry_t) + size);
+        if (!entry)
+        {
+            ret = ERR_NOMEMORY;
+            goto cleanup;
+        }
+
+        entry->size = size;
+        memcpy(entry->data, buffer, size);
+        list_append(&pipe->fifo, &entry->link);
+    }
+    else
+    {
+        const byte_t *data = (const byte_t*)buffer;
+        pipe_fifo_entry_t *entry = (pipe->fifo.prev != &pipe->fifo) ? (pipe_fifo_entry_t*)pipe->fifo.prev : NULL;
+
+        while (count < size)
+        {
+            if (!entry || entry->full)
+            {
+                entry = (pipe_fifo_entry_t*)heap_alloc(&evictable_heap, sizeof(pipe_fifo_entry_t));
+                if (!entry)
+                {
+                    ret = ERR_NOMEMORY;
+                    break;
+                }
+
+                entry->start = entry->end = 0;
+                entry->full = FALSE;
+                list_append(&pipe->fifo, &entry->link);
+            }
+
+            while ((count < size) && (entry->start != entry->end))
+            {
+                entry->data[entry->end++] = data[count++];
+                entry->end %= PIPE_BLOCK_SIZE;
+            }
+
+            if (entry->start == entry->end) entry->full = TRUE;
+        }
+    }
+
+cleanup:
+    release_lock(&pipe->lock);
+    return ret;
+}
+
+void pipe_cleanup(pipe_t *pipe)
+{
+    while (pipe->fifo.next != &pipe->fifo)
+    {
+        pipe_fifo_entry_t *entry = CONTAINER_OF(pipe->fifo.next, pipe_fifo_entry_t, link);
+        list_remove(&entry->link);
+        free(entry);
+    }
+}
+
+sysret_t syscall_create_pipeline(const char *name, dword_t flags, access_flags_t access, handle_t *handle)
 {
     dword_t ret;
     handle_t safe_handle;
-    char *safe_name = NULL;
+    const char *safe_name = NULL;
 
     if (get_previous_mode() == USER_MODE)
     {
@@ -46,35 +196,31 @@ sysret_t syscall_create_pipe(const char *name, handle_t *handle)
     }
     else
     {
-        safe_name = (char*)name;
+        safe_name = (const char*)name;
     }
 
-    pipe_t *pipe = (pipe_t*)malloc(sizeof(pipe_t));
-    if (pipe == NULL)
+    pipeline_t *pipeline = (pipeline_t*)malloc(sizeof(pipeline_t));
+    if (pipeline == NULL)
     {
         ret = ERR_NOMEMORY;
         goto cleanup;
     }
 
-    pipe->header.name = strdup(name);
-    pipe->header.type = OBJECT_PIPE;
-    pipe->lock = 0;
-    list_init(&pipe->fifo);
+    init_object(&pipeline->header, safe_name, OBJECT_PIPELINE);
+    pipeline->flags = flags;
+    pipeline->lock = 0;
+    pipeline->status = PIPELINE_IDLE;
 
-    ret = create_object(&pipe->header);
+    ret = create_object(&pipeline->header);
     if (ret != ERR_SUCCESS)
     {
-        free(pipe->header.name);
-        free(pipe);
+        free(pipeline->header.name);
+        free(pipeline);
         goto cleanup;
     }
 
-    ret = open_object(&pipe->header, 0, &safe_handle);
-    if (ret != ERR_SUCCESS)
-    {
-        dereference(&pipe->header);
-        goto cleanup;
-    }
+    ret = open_object(&pipeline->header, access, &safe_handle);
+    if (ret != ERR_SUCCESS) goto cleanup;
 
     EH_TRY
     {
@@ -82,19 +228,22 @@ sysret_t syscall_create_pipe(const char *name, handle_t *handle)
     }
     EH_CATCH
     {
+        syscall_close_object(safe_handle);
         ret = ERR_BADPTR;
     }
     EH_DONE;
 
 cleanup:
-    if (get_previous_mode() == USER_MODE) free(safe_name);
+    dereference(&pipeline->header);
+    if (get_previous_mode() == USER_MODE) free((void*)safe_name);
     return ret;
 }
 
-sysret_t syscall_open_pipe(const char *name, handle_t *handle)
+sysret_t syscall_open_pipeline(const char *name, access_flags_t access, handle_t *handle)
 {
+    dword_t ret;
     handle_t safe_handle;
-    char *safe_name = NULL;
+    const char *safe_name = NULL;
 
     if (get_previous_mode() == USER_MODE)
     {
@@ -112,10 +261,10 @@ sysret_t syscall_open_pipe(const char *name, handle_t *handle)
     }
     else
     {
-        safe_name = (char*)name;
+        safe_name = (const char*)name;
     }
 
-    dword_t ret = open_object_by_name(safe_name, OBJECT_PIPE, 0, &safe_handle);
+    ret = open_object_by_name(safe_name, OBJECT_PIPELINE, access, &safe_handle);
     if (ret != ERR_SUCCESS) goto cleanup;
 
     EH_TRY
@@ -129,62 +278,223 @@ sysret_t syscall_open_pipe(const char *name, handle_t *handle)
     EH_DONE;
 
 cleanup:
-    if (get_previous_mode() == USER_MODE) free(safe_name);
+    if (get_previous_mode() == USER_MODE) free((void*)safe_name);
     return ret;
 }
 
-sysret_t syscall_read_pipe(handle_t handle, void *buffer, dword_t size, dword_t timeout)
+static dword_t pipeline_create_pipes(pipeline_t *pipeline)
 {
-    pipe_t *pipe;
-    byte_t *safe_buffer = NULL;
+    dword_t request_flags = (pipeline->flags & PIPELINE_REQUEST_MESSAGE) ? PIPE_MESSAGE : 0;
+    dword_t response_flags = (pipeline->flags & PIPELINE_RESPONSE_MESSAGE) ? PIPE_MESSAGE : 0;
+    dword_t ret = create_pipe_internal(&pipeline->request_pipe, request_flags);
+    if (ret != ERR_SUCCESS) return ret;
+
+    if (!(pipeline->flags & PIPELINE_REQUEST_ONLY))
+    {
+        ret = create_pipe_internal(&pipeline->response_pipe, response_flags);
+        if (ret != ERR_SUCCESS)
+        {
+            dereference(&pipeline->request_pipe->header);
+            pipeline->request_pipe = NULL;
+        }
+    }
+
+    return ret;
+}
+
+static dword_t connect_to_pipeline(pipeline_t *pipeline, pipe_connection_t *conn)
+{
+    ASSERT(pipeline->lock);
+
+    dword_t ret = open_object(&pipeline->request_pipe->header, 0, &conn->request_pipe);
+    if (ret != ERR_SUCCESS) return ret;
+
+    if (pipeline->response_pipe)
+    {
+        ret = open_object(&pipeline->response_pipe->header, 0, &conn->response_pipe);
+        if (ret != ERR_SUCCESS) syscall_close_object(conn->response_pipe);
+    }
+
+    return ret;
+}
+
+sysret_t syscall_listen_pipeline(handle_t handle, dword_t timeout, pipe_connection_t *connection)
+{
+    dword_t ret;
+    process_t *proc;
 
     if (get_previous_mode() == USER_MODE)
     {
-        if (!check_usermode(buffer, size)) return ERR_BADPTR;
+        proc = get_current_process();
+    }
+    else
+    {
+        proc = kernel_process;
+    }
 
-        safe_buffer = (byte_t*)malloc(size);
-        if (safe_buffer == NULL) return ERR_NOMEMORY;
+    pipeline_t *pipeline;
+    if (!reference_by_handle(handle, OBJECT_PIPELINE, (object_t**)&pipeline)) return ERR_INVALID;
+
+    acquire_lock(&pipeline->lock);
+
+    if (pipeline->status != PIPELINE_IDLE)
+    {
+        release_lock(&pipeline->lock);
+        dereference(&pipeline->header);
+        return ERR_BUSY;
     }
-    else safe_buffer = (byte_t*)buffer;
 
-    if (!reference_by_handle(handle, OBJECT_PIPE, (object_t**)&pipe)) return ERR_INVALID;
+    pipeline->server_pid = proc->pid;
+    pipeline->client_pid = 0;
+    pipeline->request_pipe = pipeline->response_pipe = NULL;
 
-    dword_t ret = ERR_SUCCESS;
-    dword_t count = 0;
-    acquire_lock(&pipe->lock);
+    pipeline->status = PIPELINE_ACCEPTING;
+    release_lock(&pipeline->lock);
+
+    wait_result_t result = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, &pipeline->status, PIPELINE_ACCEPTING);
+    acquire_lock(&pipeline->lock);
 
-    while (count < size)
+    if (pipeline->status != PIPELINE_CONNECTING)
     {
-        if (pipe->fifo.next == NULL)
+        switch (result)
         {
-            release_lock(&pipe->lock);
+        case WAIT_CONDITION_HIT:
+            ret = pipeline->last_error;
+            break;
 
-            if (scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, (dword_t*)&pipe->fifo.next, 0) == WAIT_TIMED_OUT)
-            {
-                ret = ERR_TIMEOUT;
-                break;
-            }
+        case WAIT_TIMED_OUT:
+            ret = ERR_TIMEOUT;
+            break;
 
-            acquire_lock(&pipe->lock);
+        case WAIT_CANCELED:
+            ret = ERR_CANCELED;
         }
 
-        pipe_fifo_entry_t *entry = (pipe_fifo_entry_t*)pipe->fifo.next;
+        goto cleanup;
+    }
+
+    pipe_connection_t conn;
+    conn.server_pid = pipeline->server_pid;
+    conn.client_pid = pipeline->client_pid;
+    conn.request_pipe = conn.response_pipe = INVALID_HANDLE;
 
-        while ((count < size) && ((entry->start != entry->end) || entry->full))
+    ret = connect_to_pipeline(pipeline, &conn);
+    if (ret == ERR_SUCCESS)
+    {
+        EH_TRY
+        {
+            *connection = conn;
+        }
+        EH_CATCH
         {
-            safe_buffer[count++] = entry->data[entry->start++];
-            entry->start %= PIPE_BLOCK_SIZE;
-            entry->full = FALSE;
+            ret = ERR_BADPTR;
         }
+        EH_DONE;
+    }
+
+cleanup:
+    pipeline->status = PIPELINE_IDLE;
+
+    if (pipeline->request_pipe) dereference(&pipeline->request_pipe->header);
+    if (pipeline->response_pipe) dereference(&pipeline->response_pipe->header);
+    pipeline->request_pipe = pipeline->response_pipe = NULL;
+
+    release_lock(&pipeline->lock);
+    dereference(&pipeline->header);
+    return ret;
+}
+
+sysret_t syscall_connect_pipeline(handle_t handle, access_flags_t access, pipe_connection_t *connection)
+{
+    dword_t ret;
+    process_t *proc;
+
+    if (get_previous_mode() == USER_MODE)
+    {
+        proc = get_current_process();
+        if (!check_usermode(connection, sizeof(pipe_connection_t))) return ERR_BADPTR;
+    }
+    else
+    {
+        proc = kernel_process;
+    }
+
+    pipeline_t *pipeline = NULL;
+    if (!reference_by_handle(handle, OBJECT_PIPELINE, (object_t**)&pipeline))
+    {
+        ret = ERR_NOTFOUND;
+        goto cleanup;
+    }
+
+    acquire_lock(&pipeline->lock);
+
+    if (pipeline->status != PIPELINE_ACCEPTING)
+    {
+        ret = ERR_BUSY;
+        goto cleanup;
+    }
+
+    pipeline->client_pid = proc->pid;
+
+    ret = pipeline_create_pipes(pipeline);
+    if (ret != ERR_SUCCESS)
+    {
+        pipeline->last_error = ret;
+        goto cleanup;
+    }
+
+    pipe_connection_t conn;
+    conn.server_pid = pipeline->server_pid;
+    conn.client_pid = pipeline->client_pid;
+    conn.request_pipe = INVALID_HANDLE;
+    conn.response_pipe = INVALID_HANDLE;
+
+    ret = connect_to_pipeline(pipeline, &conn);
+    if (ret == ERR_SUCCESS)
+    {
+        pipeline->status = PIPELINE_CONNECTING;
 
-        if ((entry->start == entry->end) && !entry->full)
+        EH_TRY
+        {
+            *connection = conn;
+        }
+        EH_CATCH
         {
-            list_remove(&entry->list);
-            free(entry);
+            ret = ERR_BADPTR;
         }
+        EH_DONE;
+    }
+    else
+    {
+        pipeline->last_error = ret;
+        pipeline->status = PIPELINE_FAILED;
     }
 
-    release_lock(&pipe->lock);
+cleanup:
+    release_lock(&pipeline->lock);
+    if (pipeline) dereference(&pipeline->header);
+    return ret;
+}
+
+sysret_t syscall_read_pipe(handle_t handle, void *buffer, size_t size, dword_t timeout)
+{
+    pipe_t *pipe;
+    void *safe_buffer = NULL;
+
+    if (get_previous_mode() == USER_MODE)
+    {
+        if (!check_usermode(buffer, size)) return ERR_BADPTR;
+
+        safe_buffer = malloc(size);
+        if (safe_buffer == NULL) return ERR_NOMEMORY;
+    }
+    else
+    {
+        safe_buffer = buffer;
+    }
+
+    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);
     dereference(&pipe->header);
 
     if (get_previous_mode() == USER_MODE)
@@ -199,7 +509,7 @@ sysret_t syscall_read_pipe(handle_t handle, void *buffer, dword_t size, dword_t
     return ret;
 }
 
-sysret_t syscall_write_pipe(handle_t handle, void *buffer, dword_t size)
+sysret_t syscall_write_pipe(handle_t handle, void *buffer, size_t size)
 {
     pipe_t *pipe;
     byte_t *safe_buffer = NULL;
@@ -222,39 +532,7 @@ sysret_t syscall_write_pipe(handle_t handle, void *buffer, dword_t size)
     else safe_buffer = (byte_t*)buffer;
 
     if (!reference_by_handle(handle, OBJECT_PIPE, (object_t**)&pipe)) return ERR_INVALID;
-
-    dword_t ret = ERR_SUCCESS;
-    dword_t count = 0;
-    acquire_lock(&pipe->lock);
-
-    pipe_fifo_entry_t *entry = (pipe_fifo_entry_t*)pipe->fifo.prev;
-    while (count < size)
-    {
-        if (entry->full)
-        {
-            entry = (pipe_fifo_entry_t*)heap_alloc(&evictable_heap, sizeof(pipe_fifo_entry_t));
-            if (entry == NULL)
-            {
-                ret = ERR_NOMEMORY;
-                goto done;
-            }
-
-            entry->start = entry->end = 0;
-            entry->full = FALSE;
-            list_append(&pipe->fifo, &entry->list);
-        }
-
-        while ((count < size) && (entry->start != entry->end))
-        {
-            entry->data[entry->end++] = safe_buffer[count++];
-            entry->end %= PIPE_BLOCK_SIZE;
-        }
-
-        if (entry->start == entry->end) entry->full = TRUE;
-    }
-
-done:
-    release_lock(&pipe->lock);
+    dword_t ret = write_pipe(pipe, safe_buffer, size);
     dereference(&pipe->header);
 
     if (get_previous_mode() == USER_MODE)
@@ -268,15 +546,3 @@ done:
 
     return ret;
 }
-
-void pipe_cleanup(pipe_t *pipe)
-{
-    pipe_fifo_entry_t *entry = (pipe_fifo_entry_t*)pipe->fifo.next;
-
-    while (entry != NULL)
-    {
-        pipe_fifo_entry_t *next_entry = (pipe_fifo_entry_t*)entry->list.next;
-        free(entry);
-        entry = next_entry;
-    }
-}
index 9aa0b66868da1cd4431e1b6fed753b5992e1a37a..4bd790136cdf4b5045d0132453bacfdc18667642 100644 (file)
@@ -265,8 +265,7 @@ sysret_t syscall_create_process(const char *path, dword_t flags, process_params_
     if (proc == NULL) return ERR_NOMEMORY;
     memset(proc, 0, sizeof(process_t));
 
-    proc->header.name = NULL;
-    proc->header.type = OBJECT_PROCESS;
+    init_object(&proc->header, NULL, OBJECT_PROCESS);
 
     proc->pid = alloc_pid();
     if (proc->pid == (dword_t)-1)
@@ -288,7 +287,7 @@ sysret_t syscall_create_process(const char *path, dword_t flags, process_params_
         dword_t i;
         acquire_resource_shared(&current->handle_table_res);
 
-        proc->handle_table = (handle_info_t*)malloc(current->handle_table_size);
+        proc->handle_table = (handle_info_t*)heap_alloc(&evictable_heap, STARTUP_HANDLE_TABLE_SIZE);
         memset(proc->handle_table, 0, current->handle_table_size);
         proc->handle_table_size = current->handle_table_size;
         proc->handle_count = current->handle_count;
@@ -760,8 +759,7 @@ void process_init(char *root_directory)
     ASSERT(kernel_process != NULL);
 
     memset(kernel_process, 0, sizeof(process_t));
-    kernel_process->header.name = NULL;
-    kernel_process->header.type = OBJECT_PROCESS;
+    init_object(&kernel_process->header, NULL, OBJECT_PROCESS);
 
     ASSERT(create_object(&kernel_process->header) == ERR_SUCCESS);
 
index fa91b46dc04b660408f3efcb8e8e6c1e0f007bfd..e72e6bf05acd2ba22e29889023dbe9719ba1a8f0 100644 (file)
@@ -118,26 +118,25 @@ sysret_t syscall_create_semaphore(const char *name, dword_t init_count, dword_t
     }
 
     init_semaphore(semaphore, init_count, max_count);
-
-    semaphore->header.name = name ? strdup(safe_name) : NULL;
-    semaphore->header.type = OBJECT_SEMAPHORE;
+    init_object(&semaphore->header, name, OBJECT_SEMAPHORE);
 
     dword_t ret = create_object(&semaphore->header);
-    if (ret == ERR_SUCCESS)
-    {
-        ret = open_object(&semaphore->header, 0, &safe_handle);
-        dereference(&semaphore->header);
-    }
-
     if (ret != ERR_SUCCESS)
     {
         if (semaphore->header.name) free(semaphore->header.name);
         free(semaphore);
+        return ret;
     }
 
-    EH_TRY *handle = safe_handle;
-    EH_CATCH ret = ERR_BADPTR;
-    EH_DONE;
+    ret = open_object(&semaphore->header, 0, &safe_handle);
+    dereference(&semaphore->header);
+
+    if (ret == ERR_SUCCESS)
+    {
+        EH_TRY *handle = safe_handle;
+        EH_CATCH ret = ERR_BADPTR;
+        EH_DONE;
+    }
 
     if (get_previous_mode() == USER_MODE) free(safe_name);
     return ret;
index 1caadb54f55252a447f2dab1d605074ab5267c0e..54b7fda26c2666377727512b8de26d4dee3843f5 100644 (file)
@@ -27,6 +27,7 @@
 #include <timer.h>
 #include <power.h>
 #include <exception.h>
+#include <pipe.h>
 
 extern qword_t syscall_function(const void*, dword_t*, dword_t);
 
@@ -37,8 +38,9 @@ const void *service_table[] =
     &syscall_clock_set_time,
     &syscall_close_object,
     &syscall_commit_memory,
+    &syscall_connect_pipeline,
     &syscall_create_memory_section,
-    &syscall_create_pipe,
+    &syscall_create_pipeline,
     &syscall_create_process,
     &syscall_create_semaphore,
     &syscall_create_thread,
@@ -55,12 +57,13 @@ const void *service_table[] =
     &syscall_get_milliseconds,
     &syscall_get_nanoseconds,
     &syscall_list_directory,
+    &syscall_listen_pipeline,
     &syscall_logon_user,
     &syscall_map_memory_section,
     &syscall_mount,
     &syscall_open_file,
     &syscall_open_memory_section,
-    &syscall_open_pipe,
+    &syscall_open_pipeline,
     &syscall_open_process,
     &syscall_open_semaphore,
     &syscall_open_thread,
index ebf56cc6d8033d6873d54d7f51e85ea162483d08..8d2ee47d855d28a6b726654ac82ebbe174718d61 100644 (file)
@@ -165,8 +165,7 @@ dword_t create_thread_internal(process_t *proc, thread_state_t *initial_state, d
     thread_t *thread = (thread_t*)malloc(sizeof(thread_t));
     if (thread == NULL) return ERR_NOMEMORY;
 
-    thread->header.name = NULL;
-    thread->header.type = OBJECT_THREAD;
+    init_object(&thread->header, NULL, OBJECT_THREAD);
 
     ret = create_object(&thread->header);
     if (ret != ERR_SUCCESS)
@@ -833,8 +832,7 @@ void thread_init(void)
     thread_t *main_thread = (thread_t*)malloc(sizeof(thread_t));
     if (main_thread == NULL) KERNEL_CRASH("Cannot allocate thread object");
 
-    main_thread->header.name = NULL;
-    main_thread->header.type = OBJECT_THREAD;
+    init_object(&main_thread->header, NULL, OBJECT_THREAD);
 
     if (create_object(&main_thread->header) != ERR_SUCCESS)
     {
index e72987846e14a2639aca95bf9e95faba9502ec7b..5cdf9f55b1df364f532540090a8ef02913c183fd 100644 (file)
@@ -53,13 +53,19 @@ static dword_t add_user(dword_t uid, const char *name, dword_t *password_hash, q
     user = (user_t*)malloc(sizeof(user_t));
     if (user == NULL) return ERR_NOMEMORY;
 
-    user->header.name = strdup(name);
-    user->header.type = OBJECT_USER;
+    init_object(&user->header, name, OBJECT_USER);
     user->uid = uid;
     memcpy(user->password_hash, password_hash, sizeof(user->password_hash));
     user->privileges = privileges;
 
-    return create_object(&user->header);
+    dword_t ret = create_object(&user->header);
+    if (ret != ERR_SUCCESS)
+    {
+        free(user->header.name);
+        free(user);
+    }
+
+    return ret;
 }
 
 static void sha256_compute(byte_t *buffer, size_t size, dword_t *sum)
index a9d78e408a022d530fa5110f229a1afc56e7be97..85a30b65ea24f04a21fa1f4e14ed36d81e1f7581 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * wrappers.c
+ * wrappers.c (Automatically generated)
  *
  * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  *
@@ -44,14 +44,19 @@ sysret_t syscall_commit_memory(handle_t process, void *address, dword_t size)
     return syscall(SYSCALL_COMMIT_MEMORY, process, address, size);
 }
 
+sysret_t syscall_connect_pipeline(handle_t handle, access_flags_t access, pipe_connection_t *connection)
+{
+    return syscall(SYSCALL_CONNECT_PIPELINE, handle, access, connection);
+}
+
 sysret_t syscall_create_memory_section(const char *name, handle_t file, size_t size, dword_t flags, handle_t *handle)
 {
     return syscall(SYSCALL_CREATE_MEMORY_SECTION, name, file, size, flags, handle);
 }
 
-sysret_t syscall_create_pipe(const char *name, handle_t *handle)
+sysret_t syscall_create_pipeline(const char *name, dword_t flags,access_flags_t access,  handle_t *handle)
 {
-    return syscall(SYSCALL_CREATE_PIPE, name, handle);
+    return syscall(SYSCALL_CREATE_PIPELINE, name, flags, access, handle);
 }
 
 sysret_t syscall_create_process(const char *path, dword_t flags, process_params_t *parameters, handle_t *process_handle, handle_t *thread_handle)
@@ -134,6 +139,11 @@ sysret_t syscall_list_directory(handle_t handle, char *filename, bool_t continue
     return syscall(SYSCALL_LIST_DIRECTORY, handle, filename, continue_scan);
 }
 
+sysret_t syscall_listen_pipeline(handle_t handle, dword_t timeout, pipe_connection_t *connection)
+{
+    return syscall(SYSCALL_LISTEN_PIPELINE, handle, timeout, connection);
+}
+
 sysret_t syscall_logon_user(dword_t uid, const char *password)
 {
     return syscall(SYSCALL_LOGON_USER, uid, password);
@@ -159,9 +169,9 @@ sysret_t syscall_open_memory_section(const char *name, handle_t *handle)
     return syscall(SYSCALL_OPEN_MEMORY_SECTION, name, handle);
 }
 
-sysret_t syscall_open_pipe(const char *name, handle_t *handle)
+sysret_t syscall_open_pipeline(const char *name, access_flags_t access, handle_t *handle)
 {
-    return syscall(SYSCALL_OPEN_PIPE, name, handle);
+    return syscall(SYSCALL_OPEN_PIPELINE, name, access, handle);
 }
 
 sysret_t syscall_open_process(dword_t pid, handle_t *handle)
index 8fb5bc3a62c923124eb3fc4b8976802862fde115..a5d2ea89013cec0a2883c08b86d3e18a8cf02630 100644 (file)
@@ -31,6 +31,7 @@ typedef enum
 {
     OBJECT_FILE,
     OBJECT_FILE_INSTANCE,
+    OBJECT_PIPELINE,
     OBJECT_PIPE,
     OBJECT_PROCESS,
     OBJECT_THREAD,
diff --git a/sdk/pipe.h b/sdk/pipe.h
new file mode 100644 (file)
index 0000000..d3c9874
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * pipe.h
+ *
+ * Copyright (C) 2017 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MONOLITHIUM_PIPE_H__
+#define __MONOLITHIUM_PIPE_H__
+
+#include "object.h"
+
+#define PIPELINE_REQUEST_ONLY     (1 << 0)
+#define PIPELINE_REQUEST_MESSAGE  (1 << 1)
+#define PIPELINE_RESPONSE_MESSAGE (1 << 2)
+
+typedef struct
+{
+    dword_t server_pid;
+    dword_t client_pid;
+    handle_t request_pipe;
+    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_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_write_pipe(handle_t handle, void *buffer, dword_t size);
+
+#endif
index 4b9c680e1526661456c776576f7554dc72abfaaa..69724d92ce5520a55e81aef514eb175db9ab0948 100644 (file)
@@ -32,8 +32,9 @@ typedef enum
     SYSCALL_CLOCK_SET_TIME,
     SYSCALL_CLOSE_OBJECT,
     SYSCALL_COMMIT_MEMORY,
+    SYSCALL_CONNECT_PIPELINE,
     SYSCALL_CREATE_MEMORY_SECTION,
-    SYSCALL_CREATE_PIPE,
+    SYSCALL_CREATE_PIPELINE,
     SYSCALL_CREATE_PROCESS,
     SYSCALL_CREATE_SEMAPHORE,
     SYSCALL_CREATE_THREAD,
@@ -50,12 +51,13 @@ typedef enum
     SYSCALL_GET_MILLISECONDS,
     SYSCALL_GET_NANOSECONDS,
     SYSCALL_LIST_DIRECTORY,
+    SYSCALL_LISTEN_PIPELINE,
     SYSCALL_LOGON_USER,
     SYSCALL_MAP_MEMORY_SECTION,
     SYSCALL_MOUNT,
     SYSCALL_OPEN_FILE,
     SYSCALL_OPEN_MEMORY_SECTION,
-    SYSCALL_OPEN_PIPE,
+    SYSCALL_OPEN_PIPELINE,
     SYSCALL_OPEN_PROCESS,
     SYSCALL_OPEN_SEMAPHORE,
     SYSCALL_OPEN_THREAD,
index 64a176e28e87f5c1f915e67bf95912690c61586c..9cc90a5419224e655bef154943815dad7b903ca3 100644 (file)
@@ -102,6 +102,6 @@ sysret_t syscall_delete_user(dword_t uid);
 sysret_t syscall_set_user_id(dword_t uid);
 sysret_t syscall_revert_user(void);
 sysret_t syscall_logon_user(dword_t uid, const char *password);
-sysret_t syscall_query_user(dword_t uid, user_info_t, void *buffer, dword_t size);
+sysret_t syscall_query_user(dword_t uid, user_info_t info_type, void *buffer, dword_t size);
 
 #endif