sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
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
15
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
25struct __lock {
26 int32_t sem_id;
27 int32_t thread_id;
28 int32_t count;
29};
30
31struct __lock __lock___sfp_recursive_mutex;
32
33struct __lock __lock___atexit_recursive_mutex;
34
35struct __lock __lock___at_quick_exit_mutex;
36
37struct __lock __lock___malloc_recursive_mutex;
38
39struct __lock __lock___env_recursive_mutex;
40
41struct __lock __lock___tz_mutex;
42
43struct __lock __lock___dd_hash_mutex;
44
45struct __lock __lock___arc4random_mutex;
46
47static inline void __common_lock_init(_LOCK_T lock)
48{
49 ee_sema_t sema;
50 sema.init_count = 1;
51 sema.max_count = 1;
52 sema.option = 0;
53 sema.attr = 0;
54 sema.wait_threads = 0;
55 lock->sem_id = CreateSema(&sema);
56 lock->count = -1;
57 lock->thread_id = -1;
58}
59
60static inline void __common_lock_init_recursive(_LOCK_T lock)
61{
62 ee_sema_t sema;
63 sema.init_count = 1;
64 sema.max_count = 1;
65 sema.option = 0;
66 sema.attr = 0;
67 sema.wait_threads = 0;
68 lock->sem_id = CreateSema(&sema);
69 lock->count = 0;
70 lock->thread_id = -1;
71}
72
73static inline void __common_lock_close(_LOCK_T lock)
74{
75 DeleteSema(lock->sem_id);
76}
77
78static inline void __common_lock_close_recursive(_LOCK_T lock)
79{
80 DeleteSema(lock->sem_id);
81}
82
83void __retarget_lock_init(_LOCK_T *lock)
84{
85 _LOCK_T new_lock = (_LOCK_T)malloc(sizeof(struct __lock));
86 __common_lock_init(new_lock);
87 *lock = new_lock;
88}
89
90void __retarget_lock_init_recursive(_LOCK_T *lock)
91{
92 _LOCK_T new_lock = (_LOCK_T)malloc(sizeof(struct __lock));
93 __common_lock_init_recursive(new_lock);
94 *lock = new_lock;
95}
96
97void __retarget_lock_close(_LOCK_T lock)
98{
99 __common_lock_close(lock);
100 free(lock);
101}
102
103void __retarget_lock_close_recursive(_LOCK_T lock)
104{
105 __common_lock_close_recursive(lock);
106 free(lock);
107}
108
109void __retarget_lock_acquire(_LOCK_T lock)
110{
111 WaitSema(lock->sem_id);
112}
113
114void __retarget_lock_acquire_recursive(_LOCK_T lock)
115{
116 int32_t thread_id = GetThreadId();
117
118 /* Recursive case: this thread already owns the gate. We can read
119 * thread_id/count without the gate because only the owning thread
120 * mutates them while it holds the gate, and only the owning thread
121 * can take this branch. */
122 if (lock->count > 0 && lock->thread_id == thread_id) {
123 lock->count++;
124 return;
125 }
126
127 /* Otherwise acquire the gate for real. Only after WaitSema returns
128 * do we touch thread_id/count — putting count++ before WaitSema is
129 * what causes the classic recursive-mutex deadlock here, because a
130 * higher-priority thread preempting between count++ and WaitSema
131 * sees count>0, falls into the else branch, races past the sema, and
132 * then nobody signals it after release. */
133 WaitSema(lock->sem_id);
134 lock->thread_id = thread_id;
135 lock->count = 1;
136}
137
138int __retarget_lock_try_acquire(_LOCK_T lock)
139{
140 return PollSema(lock->sem_id) > 0 ? 0 : 1;
141}
142
143int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
144{
145 int32_t thread_id = GetThreadId();
146
147 if (lock->count > 0 && lock->thread_id == thread_id) {
148 lock->count++;
149 return 0;
150 }
151
152 if (PollSema(lock->sem_id) <= 0) {
153 return 1; /* gate not free */
154 }
155 lock->thread_id = thread_id;
156 lock->count = 1;
157 return 0;
158}
159
160void __retarget_lock_release(_LOCK_T lock)
161{
162 SignalSema(lock->sem_id);
163}
164
165void __retarget_lock_release_recursive(_LOCK_T lock)
166{
167 bool tobeRelease = false;
168 int32_t thread_id = GetThreadId();
169 if (lock->thread_id != thread_id) {
170 // error this shouldn't never happen
171 perror("Error: Trying to release a lock that was not acquired by the current thread");
172 exit(1);
173 }
174
175 tobeRelease = lock->count == 1;
176 lock->count--;
177 if (lock->count == 0) {
178 lock->thread_id = -1;
179 }
180 if (tobeRelease) {
181 SignalSema(lock->sem_id);
182 }
183}
184
185extern struct __lock __lock___malloc_recursive_mutex;
186extern struct __lock __lock___atexit_recursive_mutex;
187extern struct __lock __lock___at_quick_exit_mutex;
188extern struct __lock __lock___sfp_recursive_mutex;
189extern struct __lock __lock___env_recursive_mutex;
190extern struct __lock __lock___tz_mutex;
191extern struct __lock __lock___dd_hash_mutex;
192extern struct __lock __lock___arc4random_mutex;
193
194void __locks_init()
195{
196 /* Reset stdio initialization state so __sinit will reinitialize
197 * FILE structs and their locks on next use.
198 * _impure_data lives in .data (survives BSS clear on restart via
199 * ExecPS2), while FILE structs and locks live in .bss (zeroed).
200 * Without this, __sinit skips reinitialization and uses NULL locks. */
201 _REENT_CLEANUP(_REENT) = NULL;
202
203 _LOCK_T lock_malloc = &__lock___malloc_recursive_mutex;
204 _LOCK_T lock_atexit = &__lock___atexit_recursive_mutex;
205 _LOCK_T lock_quick_exit = &__lock___at_quick_exit_mutex;
206 _LOCK_T lock_sfp = &__lock___sfp_recursive_mutex;
207 _LOCK_T lock_env = &__lock___env_recursive_mutex;
208 _LOCK_T lock_tz = &__lock___tz_mutex;
209 _LOCK_T lock_dd_hash = &__lock___dd_hash_mutex;
210 _LOCK_T lock_arc4random = &__lock___arc4random_mutex;
211
212 __common_lock_init_recursive(lock_malloc);
213 __common_lock_init_recursive(lock_atexit);
214 __common_lock_init(lock_quick_exit);
215 __common_lock_init_recursive(lock_sfp);
216 __common_lock_init_recursive(lock_env);
217 __common_lock_init(lock_tz);
218 __common_lock_init(lock_dd_hash);
219 __common_lock_init(lock_arc4random);
220}
221
222extern struct __lock __lock___malloc_recursive_mutex;
223extern struct __lock __lock___atexit_recursive_mutex;
224extern struct __lock __lock___at_quick_exit_mutex;
225extern struct __lock __lock___sfp_recursive_mutex;
226extern struct __lock __lock___env_recursive_mutex;
227extern struct __lock __lock___tz_mutex;
228extern struct __lock __lock___dd_hash_mutex;
229extern struct __lock __lock___arc4random_mutex;
230
231void __locks_deinit()
232{
233 _LOCK_T lock_malloc = &__lock___malloc_recursive_mutex;
234 _LOCK_T lock_atexit = &__lock___atexit_recursive_mutex;
235 _LOCK_T lock_quick_exit = &__lock___at_quick_exit_mutex;
236 _LOCK_T lock_sfp = &__lock___sfp_recursive_mutex;
237 _LOCK_T lock_env = &__lock___env_recursive_mutex;
238 _LOCK_T lock_tz = &__lock___tz_mutex;
239 _LOCK_T lock_dd_hash = &__lock___dd_hash_mutex;
240 _LOCK_T lock_arc4random = &__lock___arc4random_mutex;
241
242
243 __common_lock_close_recursive(lock_malloc);
244 __common_lock_close_recursive(lock_atexit);
245 __common_lock_close(lock_quick_exit);
246 __common_lock_close_recursive(lock_sfp);
247 __common_lock_close_recursive(lock_env);
248 __common_lock_close(lock_tz);
249 __common_lock_close(lock_dd_hash);
250 __common_lock_close(lock_arc4random);
251}
Definition lock.c:25