Browse Source

Reimplement basic locking. Fix bugs.

coderain 7 months ago
parent
commit
c1387c687c
10 changed files with 245 additions and 106 deletions
  1. 1 0
      common.mk
  2. 0 2
      drivers/speaker/src/main.c
  3. 0 1
      grub.cfg
  4. 47 0
      kernel/include/lock.h
  5. 42 0
      kernel/include/semaphore.h
  6. 38 26
      kernel/include/sync.h
  7. 111 0
      kernel/src/lock.c
  8. 2 75
      kernel/src/sync.c
  9. 1 1
      manager/Makefile
  10. 3 1
      setup

+ 1 - 0
common.mk

@@ -73,6 +73,7 @@ $(OBJDIR)/%.o: $(SRCDIR)/%.c Makefile
 	$(CC) $(CFLAGS) -MMD -MP -MF $(@:$(OBJDIR)/%.o=$(DEPDIR)/%.d) -o $@ -c $<
 
 $(OBJDIR)/%.o: $(SRCDIR)/%.asm Makefile
+	mkdir -p $(dir $@)
 	$(ASM) $(ASMFLAGS) -o $@ $<
 
 $(OUTPUT_KERNEL): $(OBJECTS) $(ADDITIONAL_OBJECTS)

+ 0 - 2
drivers/speaker/src/main.c

@@ -40,8 +40,6 @@ static char_dev_driver_t speaker_driver =
     .ioctl_proc = speaker_ioctl
 };
 
-static lock_t speaker_lock = 0;
-
 static void speaker_on(dword_t frequency)
 {
     dword_t divisor = TIMER_BASE_FREQUENCY / frequency;

+ 0 - 1
grub.cfg

@@ -3,7 +3,6 @@ menuentry "Monolithium OS" {
     module2 /monolithium/drivers/acpica.drv
     module2 /monolithium/drivers/fatfs.drv
     module2 /monolithium/drivers/floppy.drv
-    module2 /monolithium/drivers/isocdfs.drv
     module2 /monolithium/drivers/ps2.drv
     module2 /monolithium/drivers/ramfs.drv
     module2 /monolithium/drivers/serial.drv

+ 47 - 0
kernel/include/lock.h

@@ -0,0 +1,47 @@
+/*
+ * lock.h
+ *
+ * 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
+ * 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 _LOCK_H_
+#define _LOCK_H_
+
+#include <sdk/defs.h>
+
+#define DECLARE_LOCK(x) lock_t x = {0}
+
+typedef uint8_t critical_t;
+
+typedef struct
+{
+    uintptr_t holder;
+    int32_t count;
+} lock_t;
+
+static inline void lock_init(lock_t *lock)
+{
+    lock->holder = lock->count = 0;
+}
+
+void enter_critical(critical_t *critical);
+void leave_critical(critical_t *critical);
+void lock_acquire(lock_t *lock);
+void lock_acquire_smart(lock_t *lock);
+void lock_acquire_shared(lock_t *lock);
+void lock_release(lock_t *lock);
+
+#endif

+ 42 - 0
kernel/include/semaphore.h

@@ -0,0 +1,42 @@
+/*
+ * semaphore.h
+ *
+ * Copyright (C) 2015 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 _SEMAPHORE_H_
+#define _SEMAPHORE_H_
+
+#include <common.h>
+#include <object.h>
+#include <sdk/sync.h>
+
+#define init_mutex(m, i) init_semaphore((m), (i), 1)
+#define wait_mutex(m, t) wait_semaphore((m), 1, (t))
+#define release_mutex(m) release_semaphore((m), 1)
+
+typedef struct
+{
+    object_t header;
+    dword_t count;
+    dword_t max_count;
+} semaphore_t, mutex_t;
+
+void init_semaphore(semaphore_t *semaphore, dword_t init_count, dword_t max_count);
+dword_t wait_semaphore(semaphore_t *semaphore, dword_t count, dword_t timeout);
+dword_t release_semaphore(semaphore_t *semaphore, dword_t count);
+
+#endif

+ 38 - 26
kernel/include/sync.h

@@ -1,7 +1,7 @@
 /*
  * sync.h
  *
- * Copyright (C) 2015 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,34 +20,46 @@
 #ifndef _SYNC_H_
 #define _SYNC_H_
 
-#include <common.h>
-#include <object.h>
-#include <sdk/sync.h>
+#include <sdk/defs.h>
+#include <lock.h>
+#include <semaphore.h>
 
-#define init_mutex(m, i) init_semaphore((m), (i), 1)
-#define wait_mutex(m, t) wait_semaphore((m), 1, (t))
-#define release_mutex(m) release_semaphore((m), 1)
+/*
+ * NOTE: This is the legacy interface for synchronization functions. New code
+ * should use lock.h and semaphore.h instead.
+ */
+
+#define lock_t qword_t
+#define resource_t qword_t
+
+static inline void acquire_lock(qword_t *lock)
+{
+    void (*proc)(void*) = (void(*)(void*))lock_acquire;
+    proc(lock);
+}
 
-typedef uint8_t critical_t;
-typedef volatile uintptr_t lock_t;
-typedef volatile uintptr_t resource_t;
+static inline void release_lock(qword_t *lock)
+{
+    void (*proc)(void*) = (void(*)(void*))lock_release;
+    proc(lock);
+}
+
+static inline void acquire_resource_shared(qword_t *resource)
+{
+    void (*proc)(void*) = (void(*)(void*))lock_acquire_shared;
+    proc(resource);
+}
+
+static inline void acquire_resource_exclusive(qword_t *resource)
+{
+    void (*proc)(void*) = (void(*)(void*))lock_acquire;
+    proc(resource);
+}
 
-typedef struct
+static inline void release_resource(qword_t *resource)
 {
-    object_t header;
-    dword_t count;
-    dword_t max_count;
-} semaphore_t, mutex_t;
-
-void enter_critical(critical_t *critical);
-void leave_critical(critical_t *critical);
-void acquire_lock(lock_t *lock);
-void release_lock(lock_t *lock);
-void acquire_resource_shared(resource_t *res);
-void acquire_resource_exclusive(resource_t *res);
-void release_resource(resource_t *res);
-void init_semaphore(semaphore_t *semaphore, dword_t init_count, dword_t max_count);
-dword_t wait_semaphore(semaphore_t *semaphore, dword_t count, dword_t timeout);
-dword_t release_semaphore(semaphore_t *semaphore, dword_t count);
+    void (*proc)(void*) = (void(*)(void*))lock_release;
+    proc(resource);
+}
 
 #endif

+ 111 - 0
kernel/src/lock.c

@@ -0,0 +1,111 @@
+/*
+ * lock.c
+ *
+ * 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
+ * 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/>.
+ */
+
+#include <thread.h>
+
+#undef lock_t
+#undef resource_t
+#include <lock.h>
+
+#define NO_HOLDER ((uintptr_t)0)
+#define MULTIPLE_HOLDERS ((uintptr_t)-1)
+#define UNKNOWN_HOLDER ((uintptr_t)-2)
+#define TEMPORARY_HOLDER ((uintptr_t)-3)
+
+void enter_critical(critical_t *critical)
+{
+    *critical = 0;
+    if (disable_ints()) *critical |= (1 << 0);
+    if (scheduler_enabled) *critical |= (1 << 1);
+
+    disable_ints();
+    scheduler_enabled = FALSE;
+}
+
+void leave_critical(critical_t *critical)
+{
+    if (*critical & (1 << 1)) scheduler_enabled = TRUE;
+    if (*critical & (1 << 0)) enable_ints();
+}
+
+void lock_acquire(lock_t *lock)
+{
+    uintptr_t new_holder = scheduler_enabled ? (uintptr_t)get_current_thread() : UNKNOWN_HOLDER;
+
+    for (;;)
+    {
+        uintptr_t old_holder = NO_HOLDER;
+
+        if (__atomic_compare_exchange(&lock->holder, &old_holder, &new_holder, FALSE, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
+        {
+            int32_t new_count = __atomic_add_fetch(&lock->count, 1, __ATOMIC_ACQUIRE);
+            ASSERT(new_count == 1);
+            return;
+        }
+
+        if (scheduler_enabled) scheduler_wait(WAIT_UNTIL_EQUAL, NO_TIMEOUT, &lock->holder, NO_HOLDER);
+    }
+}
+
+static inline void lock_acquire_smart_by(lock_t *lock, uintptr_t new_holder)
+{
+    for (;;)
+    {
+        uintptr_t old_holder = NO_HOLDER;
+        if (__atomic_compare_exchange(&lock->holder, &old_holder, &new_holder, FALSE, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)
+            || old_holder == new_holder)
+        {
+            int32_t new_count = __atomic_add_fetch(&lock->count, 1, __ATOMIC_ACQUIRE);
+            ASSERT(new_count > 0);
+            return;
+        }
+
+        if (scheduler_enabled) scheduler_wait(WAIT_UNTIL_NOT_EQUAL, NO_TIMEOUT, &lock->holder, old_holder);
+    }
+}
+
+void lock_acquire_smart(lock_t *lock)
+{
+    lock_acquire_smart_by(lock, scheduler_enabled ? (uintptr_t)get_current_thread() : UNKNOWN_HOLDER);
+}
+
+void lock_acquire_shared(lock_t *lock)
+{
+    lock_acquire_smart_by(lock, MULTIPLE_HOLDERS);
+}
+
+void lock_release(lock_t *lock)
+{
+    uintptr_t holder;
+
+    for (;;)
+    {
+        holder = __atomic_exchange_n(&lock->holder, TEMPORARY_HOLDER, __ATOMIC_ACQUIRE);
+        if (holder != TEMPORARY_HOLDER) break;
+    }
+
+    ASSERT(holder != NO_HOLDER);
+
+    int32_t new_count = __atomic_sub_fetch(&lock->count, 1, __ATOMIC_RELEASE);
+    ASSERT(new_count >= 0);
+    if (new_count == 0) holder = NO_HOLDER;
+
+    __atomic_store_n(&lock->holder, holder, __ATOMIC_RELEASE);
+    if (scheduler_enabled && holder == NO_HOLDER) syscall_yield_quantum();
+}

+ 2 - 75
kernel/src/sync.c

@@ -1,5 +1,5 @@
 /*
- * sync.c
+ * semaphore.c
  *
  * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  *
@@ -17,83 +17,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <sync.h>
+#include <semaphore.h>
 #include <thread.h>
 #include <heap.h>
 
-void enter_critical(critical_t *critical)
-{
-    *critical = 0;
-    if (disable_ints()) *critical |= (1 << 0);
-    if (scheduler_enabled) *critical |= (1 << 1);
-
-    disable_ints();
-    scheduler_enabled = FALSE;
-}
-
-void leave_critical(critical_t *critical)
-{
-    if (*critical & (1 << 1)) scheduler_enabled = TRUE;
-    if (*critical & (1 << 0)) enable_ints();
-}
-
-void acquire_lock(lock_t *lock)
-{
-    if (scheduler_enabled)
-    {
-        while (__sync_lock_test_and_set(lock, 1))
-        {
-            scheduler_wait(WAIT_UNTIL_EQUAL, NO_TIMEOUT, (uintptr_t*)lock, 0);
-        }
-    }
-    else
-    {
-        while (__sync_lock_test_and_set(lock, 1)) continue;
-    }
-}
-
-void release_lock(lock_t *lock)
-{
-    __sync_lock_release(lock);
-    if (scheduler_enabled) syscall_yield_quantum();
-}
-
-void acquire_resource_shared(resource_t *res)
-{
-    if (scheduler_enabled)
-    {
-        while (__sync_val_compare_and_swap(res, 0, 1) == 2)
-        {
-            scheduler_wait(WAIT_UNTIL_NOT_EQUAL, NO_TIMEOUT, (uintptr_t*)res, 2);
-        }
-    }
-    else
-    {
-        while (__sync_val_compare_and_swap(res, 0, 1) == 2) continue;
-    }
-}
-
-void acquire_resource_exclusive(resource_t *res)
-{
-    if (scheduler_enabled)
-    {
-        while (!__sync_bool_compare_and_swap(res, 0, 2))
-        {
-            scheduler_wait(WAIT_UNTIL_EQUAL, NO_TIMEOUT, (uintptr_t*)res, 0);
-        }
-    }
-    else
-    {
-        while (!__sync_bool_compare_and_swap(res, 0, 2)) continue;
-    }
-}
-
-void release_resource(resource_t *res)
-{
-    __sync_lock_release(res);
-    if (scheduler_enabled) syscall_yield_quantum();
-}
-
 void init_semaphore(semaphore_t *semaphore, dword_t init_count, dword_t max_count)
 {
     ASSERT(init_count <= max_count);

+ 1 - 1
manager/Makefile

@@ -23,7 +23,7 @@ DEBUG := yes
 # Flags
 CFLAGS   += -Wall -Werror -ffreestanding -nostdlib -I ../sdk -I ../crt/include
 ASMFLAGS += -felf
-LDFLAGS  += -T link.ld -L ../library -L ../crt -lmlcrt -lmlsys
+LDFLAGS  += -L ../library -L ../crt -lmlcrt -lmlsys
 
 LINK_WITH_LIBGCC := yes
 

+ 3 - 1
setup

@@ -164,12 +164,14 @@ fi
 
 echo 'Detecting installed packages...' 1>&2
 command -v gawk || packages="${packages}gawk "
-command -v i686-elf-gcc || packages="${packages}gcc "
 command -v i686-elf-ld || packages="${packages}binutils "
+command -v i686-elf-gcc || packages="${packages}gcc "
 command -v grub-mkrescue || packages="${packages}grub "
 command -v nasm || packages="${packages}nasm "
 command -v xorriso || packages="${packages}xorriso "
 
+MAKEFLAGS="$MAKEFLAGS -j `nproc`"
+
 for package in $packages
 do
     printf 'Installing package %s\n' "$package" 1>&2