PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
thmsgbx.c
1#include "intrman.h"
2#include "kerr.h"
3#include "thcommon.h"
4#include "thmsgbx.h"
5
6static void mbx_send(struct mbox *mbx, iop_message_t *msg);
7static void mbx_get_status(struct mbox *mbx, iop_mbx_status_t *info);
8
9int CreateMbx(iop_mbx_t *mbx_param)
10{
11 struct mbox *mbx;
12 int state;
13
14 if (QueryIntrContext()) {
15 return KE_ILLEGAL_CONTEXT;
16 }
17
18 if (mbx_param->attr & ~(MBA_THFIFO | MBA_THPRI | MBA_MSFIFO | MBA_MSPRI)) {
19 return KE_ILLEGAL_ATTR;
20 }
21
22 CpuSuspendIntr(&state);
23
24 mbx = heap_alloc(TAG_MBX, sizeof(*mbx));
25 if (!mbx) {
26 CpuResumeIntr(state);
27 return KE_NO_MEMORY;
28 }
29
30 mbx->tag.id = ++thctx.mbox_id;
31 mbx->event.attr = mbx_param->attr;
32 mbx->event.option = mbx_param->option;
33 list_init(&mbx->event.waiters);
34 list_insert(&thctx.mbox, &mbx->mbox_list);
35
36 CpuResumeIntr(state);
37
38 return MAKE_HANDLE(mbx);
39}
40
41int DeleteMbx(int mbxid)
42{
43 struct thread *waiter;
44 struct mbox *mbx;
45 u32 waiter_count;
46 int state;
47
48 if (QueryIntrContext()) {
49 return KE_ILLEGAL_CONTEXT;
50 }
51
52 CpuSuspendIntr(&state);
53
54 mbx = HANDLE_PTR(mbxid);
55 if (!HANDLE_VERIFY(mbxid, TAG_MBX)) {
56 CpuResumeIntr(state);
57 return KE_UNKNOWN_MBXID;
58 }
59
60 list_for_each_safe (waiter, &mbx->event.waiters, queue) {
61 waiter->saved_regs->v0 = KE_WAIT_DELETE;
62 list_remove(&waiter->queue);
63 waiter->status = THS_READY;
64 readyq_insert_back(waiter);
65 }
66
67 waiter_count = mbx->event.waiter_count;
68 list_remove(&mbx->mbox_list);
69 heap_free(&mbx->tag);
70
71 if (waiter_count) {
72 thctx.run_next = NULL;
73 return thread_leave(KE_OK, 0, state, 0);
74 }
75
76 CpuResumeIntr(state);
77
78 return KE_OK;
79}
80
81int SendMbx(int mbxid, void *msg)
82{
83 struct thread *thread;
84 struct mbox *mbx;
85 void **msg_dest;
86 int state;
87
88 if (QueryIntrContext()) {
89 return KE_ILLEGAL_CONTEXT;
90 }
91
92 CpuSuspendIntr(&state);
93
94 mbx = HANDLE_PTR(mbxid);
95 if (!HANDLE_VERIFY(mbxid, TAG_MBX)) {
96 CpuResumeIntr(state);
97 return KE_UNKNOWN_MBXID;
98 }
99
100 if (mbx->event.waiter_count == 0) {
101 mbx_send(mbx, msg);
102 CpuResumeIntr(state);
103 return KE_OK;
104 }
105
106 thread = list_first_entry(&mbx->event.waiters, struct thread, queue);
107 mbx->event.waiter_count--;
108 list_remove(&thread->queue);
109
110 msg_dest = (void **)thread->saved_regs->v0;
111
112 thread->saved_regs->v0 = KE_OK;
113
114 if (msg_dest) {
115 *msg_dest = msg;
116 }
117
118 return thread_start(thread, state);
119}
120
121int iSendMbx(int mbxid, void *msg)
122{
123 struct thread *thread;
124 struct mbox *mbx;
125 void **msg_dest;
126
127 if (!QueryIntrContext()) {
128 return KE_ILLEGAL_CONTEXT;
129 }
130
131 mbx = HANDLE_PTR(mbxid);
132 if (!HANDLE_VERIFY(mbxid, TAG_MBX)) {
133 return KE_UNKNOWN_MBXID;
134 }
135
136 if (mbx->event.waiter_count == 0) {
137 mbx_send(mbx, msg);
138 return KE_OK;
139 }
140
141 thread = list_first_entry(&mbx->event.waiters, struct thread, queue);
142 mbx->event.waiter_count--;
143 list_remove(&thread->queue);
144 msg_dest = (void **)thread->saved_regs->v0;
145 thread->saved_regs->v0 = KE_OK;
146
147 if (msg_dest) {
148 *msg_dest = msg;
149 }
150
151 readyq_insert_back(thread);
152 thctx.run_next = NULL;
153
154 return KE_OK;
155}
156
157int ReceiveMbx(void **msgvar, int mbxid)
158{
159 struct thread *thread;
160 iop_message_t *msg;
161 struct mbox *mbx;
162 int state;
163
164 if (QueryIntrContext()) {
165 return KE_ILLEGAL_CONTEXT;
166 }
167
168 if (CpuSuspendIntr(&state) == KE_CPUDI && (thctx.debug_flags & 8)) {
169 Kprintf("WARNING: ReceiveMbx:KE_CAN_NOT_WAIT\n");
170 }
171
172 mbx = HANDLE_PTR(mbxid);
173 if (!HANDLE_VERIFY(mbxid, TAG_MBX)) {
174 CpuResumeIntr(state);
175 return KE_UNKNOWN_MBXID;
176 }
177
178 if (mbx->msg_count == 0) {
179 thread = thctx.current_thread;
180 thread->status = THS_WAIT;
181 thread->wait_type = TSW_MBX;
182 thread->wait_event = &mbx->event;
183 thctx.run_next = NULL;
184
185 if (mbx->event.attr & MBA_THPRI) {
186 waitlist_insert(thread, &mbx->event, thread->priority);
187 } else {
188 list_insert(&mbx->event.waiters, &thread->queue);
189 }
190
191 return thread_leave((int)msgvar, 0, state, 1);
192 }
193
194 mbx->msg_count--;
195 msg = mbx->newest_msg->next;
196 if (msg == msg->next) {
197 mbx->newest_msg = NULL;
198 } else {
199 mbx->newest_msg->next = msg->next;
200 }
201
202 *msgvar = msg;
203
204 CpuResumeIntr(state);
205
206 return KE_OK;
207}
208
209int PollMbx(void **msgvar, int mbxid)
210{
211 iop_message_t *msg;
212 struct mbox *mbx;
213 int state;
214
215 if (QueryIntrContext()) {
216 return KE_ILLEGAL_CONTEXT;
217 }
218
219 CpuSuspendIntr(&state);
220
221 mbx = HANDLE_PTR(mbxid);
222 if (!HANDLE_VERIFY(mbxid, TAG_MBX)) {
223 CpuResumeIntr(state);
224 return KE_UNKNOWN_MBXID;
225 }
226
227 if (mbx->msg_count == 0) {
228 CpuResumeIntr(state);
229 return KE_MBOX_NOMSG;
230 }
231
232 mbx->msg_count--;
233 msg = mbx->newest_msg->next;
234 if (msg == msg->next) {
235 mbx->newest_msg = NULL;
236 } else {
237 mbx->newest_msg->next = msg->next;
238 }
239
240 *msgvar = msg;
241
242 CpuResumeIntr(state);
243
244 return KE_OK;
245}
246
247int ReferMbxStatus(int mbxid, iop_mbx_status_t *info)
248{
249 struct mbox *mbx;
250 int state;
251
252 if (QueryIntrContext()) {
253 return KE_ILLEGAL_CONTEXT;
254 }
255
256 CpuSuspendIntr(&state);
257
258 mbx = HANDLE_PTR(mbxid);
259 if (!HANDLE_VERIFY(mbxid, TAG_MBX)) {
260 CpuResumeIntr(state);
261 return KE_UNKNOWN_MBXID;
262 }
263
264 mbx_get_status(mbx, info);
265
266 CpuResumeIntr(state);
267
268 return KE_OK;
269}
270
271int iReferMbxStatus(int mbxid, iop_mbx_status_t *info)
272{
273 struct mbox *mbx;
274
275 if (!QueryIntrContext()) {
276 return KE_ILLEGAL_CONTEXT;
277 }
278
279 mbx = HANDLE_PTR(mbxid);
280 if (!HANDLE_VERIFY(mbxid, TAG_MBX)) {
281 return KE_UNKNOWN_MBXID;
282 }
283
284 mbx_get_status(mbx, info);
285
286 return KE_OK;
287}
288
289static void mbx_send(struct mbox *mbx, iop_message_t *new_msg)
290{
291 iop_message_t *latest, *oldest;
292
293 latest = mbx->newest_msg;
294 oldest = latest->next;
295
296 mbx->msg_count++;
297
298 if (!mbx->newest_msg) {
299 mbx->newest_msg = new_msg;
300 new_msg->next = new_msg;
301 return;
302 }
303
304 if ((mbx->event.attr & MBA_MSPRI) == 0) {
305 new_msg->next = oldest;
306 latest->next = new_msg;
307 mbx->newest_msg = new_msg;
308 } else {
309 // FIXME this is mostly copied out of ghidra because its awful
310 iop_message_t *piVar1;
311 iop_message_t *piVar2;
312 u32 prio;
313
314 prio = latest->next->priority;
315 piVar2 = latest;
316 piVar1 = latest->next;
317
318 while (1) {
319 if (new_msg->priority < prio) {
320 new_msg->next = piVar2->next;
321 piVar2->next = new_msg;
322 return;
323 }
324
325 piVar2 = piVar1;
326
327 if (piVar1 == latest) {
328 mbx->newest_msg = new_msg;
329 new_msg->next = piVar2->next;
330 piVar2->next = new_msg;
331 return;
332 }
333
334 prio = piVar1->next->priority;
335 piVar1 = piVar1->next;
336 }
337 }
338}
339
340static void mbx_get_status(struct mbox *mbx, iop_mbx_status_t *info)
341{
342 info->attr = mbx->event.attr;
343 info->option = mbx->event.option;
344 info->numWaitThreads = mbx->event.waiter_count;
345 info->numMessage = mbx->msg_count;
346 info->topPacket = mbx->newest_msg->next;
347}
int CpuResumeIntr(int state)
Definition intrman.c:227
int QueryIntrContext(void)
int CpuSuspendIntr(int *state)
Definition intrman.c:205