1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #ifndef _MUTEX_H_
6 #define _MUTEX_H_
7 
8 #include <pthread.h>
9 
10 #include <drivers/bug.h>
11 #include <drivers/spinlock.h>
12 #include <drivers/ddkc_log.h>
13 #include <drivers/spinlock.h>
14 
15 #define MUTEX_INIT_DONE_FLAG 0xACBDFDBC
16 
17 /**
18  * DEFINE_MUTEX(x) will define a mutex,
19  * but the mutex cannot be initialized when the mutex is global variable
20  * we use flag to record whether mutex is initialized or not
21  * */
22 struct mutex {
23 	unsigned int flag;
24 	spinlock_t s;
25 	pthread_mutex_t m;
26 };
27 
28 #define DEFINE_MUTEX(mutexname) struct mutex mutexname = {.flag = 0}
29 
30 #define __mutex_init(lock, name, key) mutex_init(lock)
31 
32 #define mutex_lock_nested(lock, depth) mutex_lock(lock)
33 
34 // TODO: need to re-implement mutex_lock_interruptible
35 #define mutex_lock_interruptible(lock) ({\
36 	pr_warn("mutex_lock_interruptible is defined as mutex_lock\r\n");\
37 	mutex_lock((lock)); \
38 	0;})
39 
mutex_init(struct mutex * lock)40 static inline void mutex_init(struct mutex *lock) {
41 	int r = 0;
42 
43 	if (lock->flag == MUTEX_INIT_DONE_FLAG) {
44 		ddkc_warn( "MUTEX:possible mutex reinit detected\r\n");
45 		BUG_ON_MSG(1, "mutex reinit detected");
46         return;
47 	}
48 
49 	spin_lock_init(&lock->s);
50 	r = pthread_mutex_init(&lock->m, NULL);
51 	if (!r) {
52 		lock->flag = MUTEX_INIT_DONE_FLAG;
53 		ddkc_loud("MUTEX:pthread_mutex_init %p success\r\n", lock);
54 		return;
55 	}
56 
57 	ddkc_err("MUTEX:pthread_mutex_init %p fails, r:%d\r\n", lock, r);
58 
59 	return;
60 }
mutex_lock(struct mutex * lock)61 static inline void mutex_lock(struct mutex *lock) {
62 	int r = 0;
63 
64 	// TODO: how to guarantee mutex_init procedure is atomic operation?
65 	if (lock->flag != MUTEX_INIT_DONE_FLAG) {
66 		ddkc_loud("MUTEX:uninitialized mutex:%p detected, init it\r\n", lock);
67 		mutex_init(lock);
68 	}
69 
70 	r = pthread_mutex_lock(&lock->m);
71 
72 	if (!r) {
73 		ddkc_loud("MUTEX:pthread_mutex_lock %p success\r\n", lock);
74 		return;
75 	}
76 	ddkc_err("MUTEX:pthread_mutex_lock %p fails, r:%d\r\n", lock, r);
77 
78 	return;
79 }
80 
mutex_trylock(struct mutex * lock)81 static inline int mutex_trylock(struct mutex *lock) {
82 	int r = 0;
83 
84 	if (lock->flag != MUTEX_INIT_DONE_FLAG) {
85 		ddkc_loud("MUTEX:uninitialized mutex:%p detected, init it\r\n", lock);
86 		mutex_init(lock);
87 	}
88 
89 	r = pthread_mutex_trylock(&lock->m);
90 
91 	if (!r) {
92 		ddkc_loud("MUTEX:pthread_mutex_trylock %p success\r\n", lock);
93 		return 1;
94 	}
95 	ddkc_err("MUTEX:pthread_mutex_trylock fails, r:%d\r\n", r);
96 
97 	return 0;
98 }
99 
mutex_unlock(struct mutex * lock)100 static inline void mutex_unlock(struct mutex *lock) {
101 	int r = pthread_mutex_unlock(&lock->m);
102 
103 	if (!r) {
104 		ddkc_loud("MUTEX:pthread_mutex_unlock %p success\r\n", lock);
105 		return;
106 	}
107 	ddkc_err("MUTEX:pthread_mutex_unlock fails, r:%d\r\n", r);
108 
109 	return;
110 }
111 
mutex_destroy(struct mutex * lock)112 static inline void mutex_destroy(struct mutex *lock) {
113 	pthread_mutex_destroy(&lock->m);
114 	lock->flag = ~MUTEX_INIT_DONE_FLAG;
115 
116 }
117 
118 #if 0
119 #define __MUTEX_INITIALIZER(lockname) \
120         { \
121           .blk_obj.blk_list.prev = &blk_obj.blk_list, \
122           .blk_obj.blk_list.next = &blk_obj.blk_list, \
123           .blk_obj.blk_policy = BLK_POLICY_PRI, \
124           .blk_obj.name       = name, \
125           #if (RHINO_CONFIG_TASK_DEL > 0) \
126           .blk_obj.cancel     = 0u, \
127           #endif \
128           .mutex_task         = NULL, \
129           .mutex_list         = NULL, \
130           .mm_alloc_flag      = K_OBJ_STATIC_ALLOC, \
131           .blk_obj.obj_type = RHINO_MUTEX_OBJ_TYPE, \
132         }
133 
134 #define DEFINE_MUTEX(mutexname) \
135     struct mutex_s mutexname = __MUTEX_INITIALIZER(mutexname)
136 #endif
137 
138 #endif //_MUTEX_H_
139