Browse Source

LibPthread: Implement a basic first pthread mutex

This patch adds these API's:

- pthread_mutex_init()
- pthread_mutex_lock()
- pthread_mutex_unlock()

No mutex attributes are supported yet, so we only do the simplest mutex
wihout recursive locking.
Andreas Kling 5 years ago
parent
commit
66a2b582c3
3 changed files with 84 additions and 7 deletions
  1. 29 0
      Libraries/LibPthread/pthread.cpp
  2. 2 1
      Libraries/LibPthread/pthread.h
  3. 53 6
      Userland/tt.cpp

+ 29 - 0
Libraries/LibPthread/pthread.cpp

@@ -1,7 +1,9 @@
+#include <AK/Atomic.h>
 #include <AK/StdLibExtras.h>
 #include <Kernel/Syscall.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <stdio.h>
 
 extern "C" {
 
@@ -27,4 +29,31 @@ int pthread_join(pthread_t thread, void** exit_value_ptr)
     int rc = syscall(SC_join_thread, thread, exit_value_ptr);
     __RETURN_WITH_ERRNO(rc, rc, -1);
 }
+
+int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attributes)
+{
+    // FIXME: Implement mutex attributes
+    UNUSED_PARAM(attributes);
+    *mutex = 0;
+    return 0;
+}
+
+int pthread_mutex_lock(pthread_mutex_t* mutex)
+{
+    auto* atomic = reinterpret_cast<Atomic<u32>*>(mutex);
+    for (;;) {
+        u32 expected = false;
+        if (atomic->compare_exchange_strong(expected, true, AK::memory_order_acq_rel))
+            return 0;
+        sched_yield();
+    }
+}
+
+int pthread_mutex_unlock(pthread_mutex_t* mutex)
+{
+    auto* atomic = reinterpret_cast<Atomic<u32>*>(mutex);
+    atomic->store(false, AK::memory_order_release);
+    return 0;
+}
+
 }

+ 2 - 1
Libraries/LibPthread/pthread.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <sched.h>
+#include <stdint.h>
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
@@ -8,7 +9,7 @@ __BEGIN_DECLS
 typedef int pthread_t;
 typedef void* pthread_key_t;
 typedef void* pthread_once_t;
-typedef void* pthread_mutex_t;
+typedef uint32_t pthread_mutex_t;
 typedef void* pthread_attr_t;
 typedef void* pthread_mutexattr_t;
 typedef void* pthread_cond_t;

+ 53 - 6
Userland/tt.cpp

@@ -1,15 +1,24 @@
 #include <pthread.h>
 #include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
 
-int main(int, char**)
+static int mutex_test();
+
+int main(int argc, char** argv)
 {
+    if (argc == 2 && *argv[1] == 'm')
+        return mutex_test();
+
     printf("Hello from the first thread!\n");
     pthread_t thread_id;
-    int rc = pthread_create(&thread_id, nullptr, [](void*) -> void* {
-        printf("Hi there, from the second thread!\n");
-        pthread_exit((void*)0xDEADBEEF);
-        return nullptr;
-    }, nullptr);
+    int rc = pthread_create(
+        &thread_id, nullptr, [](void*) -> void* {
+            printf("Hi there, from the second thread!\n");
+            pthread_exit((void*)0xDEADBEEF);
+            return nullptr;
+        },
+        nullptr);
     if (rc < 0) {
         perror("pthread_create");
         return 1;
@@ -23,3 +32,41 @@ int main(int, char**)
     printf("Okay, joined and got retval=%p\n", retval);
     return 0;
 }
+
+static pthread_mutex_t mutex;
+
+int mutex_test()
+{
+    int rc = pthread_mutex_init(&mutex, nullptr);
+    if (rc < 0) {
+        perror("pthread_mutex_init");
+        return 1;
+    }
+    pthread_t thread_id;
+    rc = pthread_create(
+        &thread_id, nullptr, [](void*) -> void* {
+            printf("I'm the secondary thread :^)\n");
+            for (;;) {
+                pthread_mutex_lock(&mutex);
+                printf("Second thread stole mutex\n");
+                sleep(1);
+                printf("Second thread giving back mutex\n");
+                pthread_mutex_unlock(&mutex);
+                sleep(1);
+            }
+            pthread_exit((void*)0xDEADBEEF);
+            return nullptr;
+        },
+        nullptr);
+    if (rc < 0) {
+        perror("pthread_create");
+        return 1;
+    }
+    for (;;) {
+        pthread_mutex_lock(&mutex);
+        printf("Obnoxious spam!\n");
+        pthread_mutex_unlock(&mutex);
+        usleep(10000);
+    }
+    return 0;
+}