PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
thsemap.c
1#include "thcommon.h"
2#include "thsemap.h"
3#include "kerr.h"
4#include "intrman.h"
5
6static void sema_get_status(struct semaphore *sema, iop_sema_info_t *info);
7
8int CreateSema(iop_sema_t *sema_params)
9{
10 struct semaphore *sema;
11 int state;
12
13 if (QueryIntrContext()) {
14 return KE_ILLEGAL_CONTEXT;
15 }
16
17 if (sema_params->attr & ~(SA_THFIFO | SA_THPRI | SA_IHTHPRI)) {
18 return KE_ILLEGAL_ATTR;
19 }
20
21 CpuSuspendIntr(&state);
22
23 sema = heap_alloc(TAG_SEMA, sizeof(*sema));
24 if (!sema) {
25 CpuResumeIntr(state);
26 return KE_NO_MEMORY;
27 }
28
29 sema->tag.id = ++thctx.sema_id;
30 sema->event.attr = sema_params->attr;
31 sema->event.option = sema_params->option;
32 sema->count = sema_params->initial;
33 sema->initial_count = sema_params->initial;
34 sema->max_count = sema_params->max;
35
36 list_init(&sema->event.waiters);
37
38 list_insert(&thctx.semaphore, &sema->sema_list);
39
40 CpuResumeIntr(state);
41
42 return MAKE_HANDLE(sema);
43}
44
45int DeleteSema(int semid)
46{
47 struct semaphore *sema;
48 struct thread *waiter;
49 u32 waiter_count;
50 int state;
51
52 if (QueryIntrContext()) {
53 return KE_ILLEGAL_CONTEXT;
54 }
55
56 CpuSuspendIntr(&state);
57
58 sema = HANDLE_PTR(semid);
59 if (!HANDLE_VERIFY(semid, TAG_SEMA)) {
60 CpuResumeIntr(state);
61 return KE_UNKNOWN_SEMID;
62 }
63
64 list_for_each_safe (waiter, &sema->event.waiters, queue) {
65 waiter->saved_regs->v0 = KE_WAIT_DELETE;
66 waiter->status = THS_READY;
67 list_remove(&waiter->queue);
68 readyq_insert_back(waiter);
69 }
70
71 waiter_count = sema->event.waiter_count;
72 list_remove(&sema->sema_list);
73 heap_free(&sema->tag);
74
75 if (waiter_count) {
76 thctx.run_next = NULL;
77 return thread_leave(KE_OK, 0, state, 0);
78 }
79
80 CpuResumeIntr(state);
81
82 return KE_OK;
83}
84
85int SignalSema(int semid)
86{
87 struct semaphore *sema;
88 struct thread *thread;
89 int state;
90
91 if (QueryIntrContext()) {
92 return KE_ILLEGAL_CONTEXT;
93 }
94
95 CpuSuspendIntr(&state);
96
97 sema = HANDLE_PTR(semid);
98 if (!HANDLE_VERIFY(semid, TAG_SEMA)) {
99 CpuResumeIntr(state);
100 return KE_UNKNOWN_SEMID;
101 }
102
103 if (sema->event.waiter_count > 0) {
104 thread = list_first_entry(&sema->event.waiters, struct thread, queue);
105 sema->event.waiter_count--;
106 list_remove(&thread->queue);
107 thread->status = THS_READY;
108
109 return thread_start(thread, state);
110 }
111
112 if (sema->count >= sema->max_count) {
113 CpuResumeIntr(state);
114 return KE_SEMA_OVF;
115 }
116
117 sema->count++;
118
119 CpuResumeIntr(state);
120
121 return KE_OK;
122}
123
124int iSignalSema(int semid)
125{
126 struct semaphore *sema;
127 struct thread *thread;
128
129 if (!QueryIntrContext()) {
130 return KE_ILLEGAL_CONTEXT;
131 }
132
133 sema = HANDLE_PTR(semid);
134 if (!HANDLE_VERIFY(semid, TAG_SEMA)) {
135 return KE_UNKNOWN_SEMID;
136 }
137
138 if (sema->event.waiter_count > 0) {
139 thread = list_first_entry(&sema->event.waiters, struct thread, queue);
140 sema->event.waiter_count--;
141 list_remove(&thread->queue);
142 thread->saved_regs->v0 = KE_OK;
143 thread->status = THS_READY;
144 readyq_insert_back(thread);
145 thctx.run_next = 0;
146
147 return KE_OK;
148 }
149
150 if (sema->count >= sema->max_count) {
151 return KE_SEMA_OVF;
152 }
153
154 sema->count++;
155
156 return KE_OK;
157}
158
159int WaitSema(int semid)
160{
161 struct semaphore *sema;
162 struct thread *thread;
163 int state;
164
165 if (QueryIntrContext()) {
166 return KE_ILLEGAL_CONTEXT;
167 }
168
169 if (CpuSuspendIntr(&state) == KE_CPUDI && (thctx.debug_flags & 8)) {
170 Kprintf("WARNING: DelayThread KE_CAN_NOT_WAIT\n");
171 }
172
173 check_thread_stack();
174
175 sema = HANDLE_PTR(semid);
176 if (!HANDLE_VERIFY(semid, TAG_SEMA)) {
177 CpuResumeIntr(state);
178 return KE_UNKNOWN_SEMID;
179 }
180
181 thread = thctx.current_thread;
182
183 if (sema->count >= 1) {
184 sema->count--;
185 CpuResumeIntr(state);
186 return KE_OK;
187 }
188
189 thread->status = THS_WAIT;
190 thread->wait_type = TSW_SEMA;
191 thread->wait_event = &sema->event;
192 thctx.run_next = NULL;
193 sema->event.waiter_count++;
194
195 if (sema->event.attr & SA_THPRI) {
196 // originally just a loop (or inlined)
197 // i don't see why not to use this function though
198 waitlist_insert(thread, &sema->event, thread->priority);
199 } else {
200 list_insert(&sema->event.waiters, &thread->queue);
201 }
202
203 return thread_leave(KE_OK, 0, state, 1);
204}
205
206int PollSema(int semid)
207{
208 struct semaphore *sema;
209 int state;
210
211 if (QueryIntrContext()) {
212 return KE_ILLEGAL_CONTEXT;
213 }
214
215 CpuSuspendIntr(&state);
216
217 sema = HANDLE_PTR(semid);
218 if (!HANDLE_VERIFY(semid, TAG_SEMA)) {
219 CpuResumeIntr(state);
220 return KE_UNKNOWN_SEMID;
221 }
222
223 if (sema->count == 0) {
224 CpuResumeIntr(state);
225 return KE_SEMA_ZERO;
226 }
227
228 sema->count--;
229
230 CpuResumeIntr(state);
231 return KE_OK;
232}
233
234int ReferSemaStatus(int semid, iop_sema_info_t *info)
235{
236 struct semaphore *sema;
237 int state;
238
239 if (QueryIntrContext()) {
240 return KE_ILLEGAL_CONTEXT;
241 }
242
243 CpuSuspendIntr(&state);
244
245 sema = HANDLE_PTR(semid);
246 if (!HANDLE_VERIFY(semid, TAG_SEMA)) {
247 CpuResumeIntr(state);
248 return KE_UNKNOWN_SEMID;
249 }
250
251 sema_get_status(sema, info);
252
253 CpuResumeIntr(state);
254
255 return KE_OK;
256}
257
258int iReferSemaStatus(int semid, iop_sema_info_t *info)
259{
260 struct semaphore *sema;
261
262 if (!QueryIntrContext()) {
263 return KE_ILLEGAL_CONTEXT;
264 }
265
266 sema = HANDLE_PTR(semid);
267 if (!HANDLE_VERIFY(semid, TAG_SEMA)) {
268 return KE_UNKNOWN_SEMID;
269 }
270
271 sema_get_status(sema, info);
272
273 return KE_OK;
274}
275
276static void sema_get_status(struct semaphore *sema, iop_sema_info_t *info)
277{
278 info->attr = sema->event.attr;
279 info->current = sema->count;
280 info->max = sema->max_count;
281 info->initial = sema->initial_count;
282 info->numWaitThreads = sema->event.waiter_count;
283 info->option = sema->event.option;
284}
int CpuResumeIntr(int state)
Definition intrman.c:227
int QueryIntrContext(void)
int CpuSuspendIntr(int *state)
Definition intrman.c:205