PS2SDK
PS2 Homebrew Libraries
lock.c
Go to the documentation of this file.
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <reent.h>
21 #include <sys/lock.h>
22 #include <kernel.h>
23 
24 // Structure representing the lock
25 struct __lock {
26  int32_t sem_id;
27  int32_t thread_id;
28  int32_t count;
29 };
30 
31 #ifdef F___lock___sfp_recursive_mutex
32 struct __lock __lock___sfp_recursive_mutex;
33 #endif
34 
35 #ifdef F___lock___atexit_recursive_mutex
36 struct __lock __lock___atexit_recursive_mutex;
37 #endif
38 
39 #ifdef F___lock___at_quick_exit_mutex
40 struct __lock __lock___at_quick_exit_mutex;
41 #endif
42 
43 #ifdef F___lock___malloc_recursive_mutex
44 struct __lock __lock___malloc_recursive_mutex;
45 #endif
46 
47 #ifdef F___lock___env_recursive_mutex
48 struct __lock __lock___env_recursive_mutex;
49 #endif
50 
51 #ifdef F___lock___tz_mutex
52 struct __lock __lock___tz_mutex;
53 #endif
54 
55 #ifdef F___lock___dd_hash_mutex
56 struct __lock __lock___dd_hash_mutex;
57 #endif
58 
59 #ifdef F___lock___arc4random_mutex
60 struct __lock __lock___arc4random_mutex;
61 #endif
62 
63 static inline void __common_lock_init(_LOCK_T lock)
64 {
65  ee_sema_t sema;
66  sema.init_count = 1;
67  sema.max_count = 1;
68  sema.option = 0;
69  sema.attr = 0;
70  sema.wait_threads = 0;
71  lock->sem_id = CreateSema(&sema);
72  lock->count = -1;
73  lock->thread_id = -1;
74 }
75 
76 static inline void __common_lock_init_recursive(_LOCK_T lock)
77 {
78  ee_sema_t sema;
79  sema.init_count = 1;
80  sema.max_count = 1;
81  sema.option = 0;
82  sema.attr = 0;
83  sema.wait_threads = 0;
84  lock->sem_id = CreateSema(&sema);
85  lock->count = 0;
86  lock->thread_id = -1;
87 }
88 
89 static inline void __common_lock_close(_LOCK_T lock)
90 {
91  DeleteSema(lock->sem_id);
92 }
93 
94 static inline void __common_lock_close_recursive(_LOCK_T lock)
95 {
96  DeleteSema(lock->sem_id);
97 }
98 
99 #ifdef F___retarget_lock_init
100 void __retarget_lock_init(_LOCK_T *lock)
101 {
102  _LOCK_T new_lock = (_LOCK_T)malloc(sizeof(struct __lock));
103  __common_lock_init(new_lock);
104  *lock = new_lock;
105 }
106 #endif
107 
108 #ifdef F___retarget_lock_init_recursive
109 void __retarget_lock_init_recursive(_LOCK_T *lock)
110 {
111  _LOCK_T new_lock = (_LOCK_T)malloc(sizeof(struct __lock));
112  __common_lock_init_recursive(new_lock);
113  *lock = new_lock;
114 }
115 #endif
116 
117 #ifdef F___retarget_lock_close
118 void __retarget_lock_close(_LOCK_T lock)
119 {
120  __common_lock_close(lock);
121  free(lock);
122 }
123 #endif
124 
125 #ifdef F___retarget_lock_close_recursive
126 void __retarget_lock_close_recursive(_LOCK_T lock)
127 {
128  __common_lock_close_recursive(lock);
129  free(lock);
130 }
131 #endif
132 
133 #ifdef F___retarget_lock_acquire
134 void __retarget_lock_acquire(_LOCK_T lock)
135 {
136  WaitSema(lock->sem_id);
137 }
138 #endif
139 
140 #ifdef F___retarget_lock_acquire_recursive
141 void __retarget_lock_acquire_recursive(_LOCK_T lock)
142 {
143  int32_t thread_id = GetThreadId();
144 
145  /* Recursive case: this thread already owns the gate. We can read
146  * thread_id/count without the gate because only the owning thread
147  * mutates them while it holds the gate, and only the owning thread
148  * can take this branch. */
149  if (lock->count > 0 && lock->thread_id == thread_id) {
150  lock->count++;
151  return;
152  }
153 
154  /* Otherwise acquire the gate for real. Only after WaitSema returns
155  * do we touch thread_id/count — putting count++ before WaitSema is
156  * what causes the classic recursive-mutex deadlock here, because a
157  * higher-priority thread preempting between count++ and WaitSema
158  * sees count>0, falls into the else branch, races past the sema, and
159  * then nobody signals it after release. */
160  WaitSema(lock->sem_id);
161  lock->thread_id = thread_id;
162  lock->count = 1;
163 }
164 #endif
165 
166 #ifdef F___retarget_lock_try_acquire
167 int __retarget_lock_try_acquire(_LOCK_T lock)
168 {
169  return PollSema(lock->sem_id) > 0 ? 0 : 1;
170 }
171 #endif
172 
173 #ifdef F___retarget_lock_try_acquire_recursive
174 int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
175 {
176  int32_t thread_id = GetThreadId();
177 
178  if (lock->count > 0 && lock->thread_id == thread_id) {
179  lock->count++;
180  return 0;
181  }
182 
183  if (PollSema(lock->sem_id) <= 0) {
184  return 1; /* gate not free */
185  }
186  lock->thread_id = thread_id;
187  lock->count = 1;
188  return 0;
189 }
190 #endif
191 
192 #ifdef F___retarget_lock_release
193 void __retarget_lock_release(_LOCK_T lock)
194 {
195  SignalSema(lock->sem_id);
196 }
197 #endif
198 
199 #ifdef F___retarget_lock_release_recursive
200 void __retarget_lock_release_recursive(_LOCK_T lock)
201 {
202  bool tobeRelease = false;
203  int32_t thread_id = GetThreadId();
204  if (lock->thread_id != thread_id) {
205  // error this shouldn't never happen
206  perror("Error: Trying to release a lock that was not acquired by the current thread");
207  exit(1);
208  }
209 
210  tobeRelease = lock->count == 1;
211  lock->count--;
212  if (lock->count == 0) {
213  lock->thread_id = -1;
214  }
215  if (tobeRelease) {
216  SignalSema(lock->sem_id);
217  }
218 }
219 #endif
220 
221 #ifdef F___locks_init
222 extern struct __lock __lock___malloc_recursive_mutex;
223 extern struct __lock __lock___atexit_recursive_mutex;
224 extern struct __lock __lock___at_quick_exit_mutex;
225 extern struct __lock __lock___sfp_recursive_mutex;
226 extern struct __lock __lock___env_recursive_mutex;
227 extern struct __lock __lock___tz_mutex;
228 extern struct __lock __lock___dd_hash_mutex;
229 extern struct __lock __lock___arc4random_mutex;
230 
231 void __locks_init()
232 {
233  /* Reset stdio initialization state so __sinit will reinitialize
234  * FILE structs and their locks on next use.
235  * _impure_data lives in .data (survives BSS clear on restart via
236  * ExecPS2), while FILE structs and locks live in .bss (zeroed).
237  * Without this, __sinit skips reinitialization and uses NULL locks. */
238  _REENT_CLEANUP(_REENT) = NULL;
239 
240  _LOCK_T lock_malloc = &__lock___malloc_recursive_mutex;
241  _LOCK_T lock_atexit = &__lock___atexit_recursive_mutex;
242  _LOCK_T lock_quick_exit = &__lock___at_quick_exit_mutex;
243  _LOCK_T lock_sfp = &__lock___sfp_recursive_mutex;
244  _LOCK_T lock_env = &__lock___env_recursive_mutex;
245  _LOCK_T lock_tz = &__lock___tz_mutex;
246  _LOCK_T lock_dd_hash = &__lock___dd_hash_mutex;
247  _LOCK_T lock_arc4random = &__lock___arc4random_mutex;
248 
249  __common_lock_init_recursive(lock_malloc);
250  __common_lock_init_recursive(lock_atexit);
251  __common_lock_init(lock_quick_exit);
252  __common_lock_init_recursive(lock_sfp);
253  __common_lock_init_recursive(lock_env);
254  __common_lock_init(lock_tz);
255  __common_lock_init(lock_dd_hash);
256  __common_lock_init(lock_arc4random);
257 }
258 #endif
259 
260 #ifdef F___locks_deinit
261 extern struct __lock __lock___malloc_recursive_mutex;
262 extern struct __lock __lock___atexit_recursive_mutex;
263 extern struct __lock __lock___at_quick_exit_mutex;
264 extern struct __lock __lock___sfp_recursive_mutex;
265 extern struct __lock __lock___env_recursive_mutex;
266 extern struct __lock __lock___tz_mutex;
267 extern struct __lock __lock___dd_hash_mutex;
268 extern struct __lock __lock___arc4random_mutex;
269 
270 void __locks_deinit()
271 {
272  _LOCK_T lock_malloc = &__lock___malloc_recursive_mutex;
273  _LOCK_T lock_atexit = &__lock___atexit_recursive_mutex;
274  _LOCK_T lock_quick_exit = &__lock___at_quick_exit_mutex;
275  _LOCK_T lock_sfp = &__lock___sfp_recursive_mutex;
276  _LOCK_T lock_env = &__lock___env_recursive_mutex;
277  _LOCK_T lock_tz = &__lock___tz_mutex;
278  _LOCK_T lock_dd_hash = &__lock___dd_hash_mutex;
279  _LOCK_T lock_arc4random = &__lock___arc4random_mutex;
280 
281 
282  __common_lock_close_recursive(lock_malloc);
283  __common_lock_close_recursive(lock_atexit);
284  __common_lock_close(lock_quick_exit);
285  __common_lock_close_recursive(lock_sfp);
286  __common_lock_close_recursive(lock_env);
287  __common_lock_close(lock_tz);
288  __common_lock_close(lock_dd_hash);
289  __common_lock_close(lock_arc4random);
290 }
291 #endif
kernel.h
t_ee_sema
Definition: kernel.h:193
stdio.h
stdlib.h
__lock
Definition: lock.c:25