PS2SDK
PS2 Homebrew Libraries
thsemap.c
1 #include "thcommon.h"
2 #include "thsemap.h"
3 #include "kerr.h"
4 #include "intrman.h"
5 
6 static void sema_get_status(struct semaphore *sema, iop_sema_info_t *info);
7 
8 int 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 
45 int 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 
85 int 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 
124 int 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 
159 int 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 
206 int 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 
234 int 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 
258 int 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 
276 static 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 }
iop_sema_t
Definition: thsemap.h:38
s_info
Definition: xprintf.c:78
semaphore
Definition: thcommon.h:88
thread
Definition: thcommon.h:143
QueryIntrContext
int QueryIntrContext(void)
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
thsemap.h
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
intrman.h
iop_sema_info_t
Definition: thsemap.h:46
kerr.h