Serenity Operating System
1/*
2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2021, kleines Filmröllchen <malu.bertsch@gmail.com>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <AK/Assertions.h>
11#include <AK/Noncopyable.h>
12#include <AK/Types.h>
13#include <pthread.h>
14
15namespace Threading {
16
17class Mutex {
18 AK_MAKE_NONCOPYABLE(Mutex);
19 AK_MAKE_NONMOVABLE(Mutex);
20 friend class ConditionVariable;
21
22public:
23 Mutex()
24 : m_lock_count(0)
25 {
26#ifndef AK_OS_SERENITY
27 pthread_mutexattr_t attr;
28 pthread_mutexattr_init(&attr);
29 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
30 pthread_mutex_init(&m_mutex, &attr);
31#endif
32 }
33 ~Mutex()
34 {
35 VERIFY(m_lock_count == 0);
36 // FIXME: pthread_mutex_destroy() is not implemented.
37 }
38
39 void lock();
40 void unlock();
41
42private:
43#ifdef AK_OS_SERENITY
44 pthread_mutex_t m_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
45#else
46 pthread_mutex_t m_mutex;
47#endif
48 unsigned m_lock_count { 0 };
49};
50
51class MutexLocker {
52 AK_MAKE_NONCOPYABLE(MutexLocker);
53 AK_MAKE_NONMOVABLE(MutexLocker);
54
55public:
56 ALWAYS_INLINE explicit MutexLocker(Mutex& mutex)
57 : m_mutex(mutex)
58 {
59 lock();
60 }
61 ALWAYS_INLINE ~MutexLocker()
62 {
63 unlock();
64 }
65 ALWAYS_INLINE void unlock() { m_mutex.unlock(); }
66 ALWAYS_INLINE void lock() { m_mutex.lock(); }
67
68private:
69 Mutex& m_mutex;
70};
71
72ALWAYS_INLINE void Mutex::lock()
73{
74 pthread_mutex_lock(&m_mutex);
75 m_lock_count++;
76}
77
78ALWAYS_INLINE void Mutex::unlock()
79{
80 VERIFY(m_lock_count > 0);
81 // FIXME: We need to protect the lock count with the mutex itself.
82 // This may be bad because we're not *technically* unlocked yet,
83 // but we're not handling any errors from pthread_mutex_unlock anyways.
84 m_lock_count--;
85 pthread_mutex_unlock(&m_mutex);
86}
87
88}