PS2SDK
PS2 Homebrew Libraries
thfpool.c
1 #include "intrman.h"
2 #include "kerr.h"
3 #include "thcommon.h"
4 #include "thpool.h"
5 
6 static void fpl_block_free(struct fpool *fpl, struct fpl_block *block);
7 static struct fpl_block *fpl_block_alloc(struct fpool *fpl);
8 static void fpl_get_info(struct fpool *fpl, iop_fpl_info_t *info);
9 
10 int CreateFpl(iop_fpl_param *param)
11 {
12  struct fpool *fpl;
13  u32 block_size, mem_size;
14  int state;
15  void *mem;
16 
17  if (QueryIntrContext()) {
18  return KE_ILLEGAL_CONTEXT;
19  }
20 
21  if (param->attr & ~(FA_THFIFO | FA_THPRI | FA_MEMBTM)) {
22  return KE_ILLEGAL_ATTR;
23  }
24 
25  if (param->block_size == 0 || param->blocks == 0) {
26  return KE_ILLEGAL_MEMSIZE;
27  }
28 
29  CpuSuspendIntr(&state);
30 
31  block_size = ALIGN(param->block_size);
32  mem_size = block_size * param->blocks;
33 
34  mem = AllocSysMemory((param->attr & FA_MEMBTM) >> 9, mem_size, NULL);
35  if (!mem) {
36  CpuResumeIntr(state);
37  return KE_NO_MEMORY;
38  }
39 
40  fpl = heap_alloc(TAG_FPL, sizeof(*fpl));
41  if (!fpl) {
42  FreeSysMemory(mem);
43  CpuResumeIntr(state);
44  return KE_NO_MEMORY;
45  }
46 
47  fpl->memory = mem;
48  fpl->block_size = param->block_size;
49  fpl->blocks = param->blocks;
50  fpl->mem_size = mem_size;
51  fpl->event.attr = param->attr;
52  fpl->event.option = param->option;
53 
54  list_init(&fpl->event.waiters);
55  list_insert(&thctx.fpool, &fpl->fpl_list);
56 
57  fpl->free = NULL;
58  for (int i = 0; i < param->blocks; i++, mem += block_size) {
59  fpl_block_free(fpl, mem);
60  }
61 
62  CpuResumeIntr(state);
63 
64  return MAKE_HANDLE(fpl);
65 }
66 
67 int DeleteFpl(int fplId)
68 {
69  struct thread *waiter;
70  struct fpool *fpl;
71  u32 waiter_count;
72  int state;
73 
74  if (QueryIntrContext()) {
75  return KE_ILLEGAL_CONTEXT;
76  }
77 
78  CpuSuspendIntr(&state);
79  fpl = HANDLE_PTR(fplId);
80  if (!HANDLE_VERIFY(fplId, TAG_FPL)) {
81  CpuResumeIntr(state);
82  return KE_UNKNOWN_FPLID;
83  }
84 
85  list_for_each_safe (waiter, &fpl->event.waiters, queue) {
86  waiter->saved_regs->v0 = KE_WAIT_DELETE;
87  waiter->status = THS_READY;
88  list_remove(&waiter->queue);
89  readyq_insert_back(waiter);
90  }
91 
92  waiter_count = fpl->event.waiter_count;
93  FreeSysMemory(fpl->memory);
94  list_remove(&fpl->fpl_list);
95  heap_free(&fpl->tag);
96 
97  if (waiter_count) {
98  thctx.run_next = NULL;
99  return thread_leave(KE_OK, 0, state, 0);
100  }
101 
102  CpuResumeIntr(state);
103 
104  return KE_OK;
105 }
106 
107 void *AllocateFpl(int fplId)
108 {
109  struct thread *thread;
110  struct fpool *fpl;
111  void *block;
112  int state;
113 
114  if (QueryIntrContext()) {
115  return (void *)KE_ILLEGAL_CONTEXT;
116  }
117 
118  if (CpuSuspendIntr(&state) == KE_CPUDI && (thctx.debug_flags & 8)) {
119  Kprintf("WARNING: AllocateFpl KE_CAN_NOT_WAIT\n");
120  }
121 
122  fpl = HANDLE_PTR(fplId);
123  if (!HANDLE_VERIFY(fplId, TAG_FPL)) {
124  CpuResumeIntr(state);
125  return (void *)KE_UNKNOWN_FPLID;
126  }
127 
128  if (fpl->free) {
129  block = fpl_block_alloc(fpl);
130  CpuResumeIntr(state);
131  return block;
132  }
133 
134  thread = thctx.current_thread;
135 
136  thread->status = THS_WAIT;
137  thread->wait_type = TSW_FPL;
138  thread->wait_event = &fpl->event;
139  thctx.run_next = NULL;
140 
141  fpl->event.waiter_count++;
142 
143  if (fpl->event.attr & FA_THPRI) {
144  waitlist_insert(thread, &fpl->event, thread->priority);
145  } else {
146  list_insert(&fpl->event.waiters, &thread->queue);
147  }
148 
149  return (void *)thread_leave(KE_OK, 0, state, 1);
150 }
151 
152 void *pAllocateFpl(int fplId)
153 {
154  struct fpool *fpl;
155  void *block;
156  int state;
157 
158  if (QueryIntrContext()) {
159  return (void *)KE_ILLEGAL_CONTEXT;
160  }
161 
162  CpuSuspendIntr(&state);
163 
164  fpl = HANDLE_PTR(fplId);
165  if (!HANDLE_VERIFY(fplId, TAG_FPL)) {
166  CpuResumeIntr(state);
167  return (void *)KE_UNKNOWN_FPLID;
168  }
169 
170  if (!fpl->free) {
171  CpuResumeIntr(state);
172  return (void *)KE_NO_MEMORY;
173  }
174 
175  block = fpl_block_alloc(fpl);
176  CpuResumeIntr(state);
177 
178  return block;
179 }
180 
181 void *ipAllocateFpl(int fplId)
182 {
183  struct fpool *fpl;
184 
185  if (!QueryIntrContext()) {
186  return (void *)KE_ILLEGAL_CONTEXT;
187  }
188 
189  fpl = HANDLE_PTR(fplId);
190  if (!HANDLE_VERIFY(fplId, TAG_FPL)) {
191  return (void *)KE_UNKNOWN_FPLID;
192  }
193 
194  if (!fpl->free) {
195  return (void *)KE_NO_MEMORY;
196  }
197 
198  return fpl_block_alloc(fpl);
199 }
200 
201 int FreeFpl(int fplId, void *memory)
202 {
203  struct thread *waiter;
204  struct fpool *fpl;
205  int state;
206 
207  if (QueryIntrContext()) {
208  return KE_ILLEGAL_CONTEXT;
209  }
210 
211  CpuSuspendIntr(&state);
212  fpl = HANDLE_PTR(fplId);
213  if (!HANDLE_VERIFY(fplId, TAG_FPL)) {
214  CpuResumeIntr(state);
215  return KE_UNKNOWN_FPLID;
216  }
217 
218  if (memory < fpl->memory || memory >= (fpl->memory + fpl->mem_size)) {
219  return KE_ILLEGAL_MEMBLOCK;
220  }
221 
222  if (fpl->event.waiter_count) {
223  waiter = list_first_entry(&fpl->event.waiters, struct thread, queue);
224  fpl->event.waiter_count--;
225  list_remove(&waiter->queue);
226  waiter->status = THS_READY;
227  waiter->saved_regs->v0 = (u32)memory;
228 
229  return thread_start(waiter, state);
230  }
231 
232  fpl_block_free(fpl, memory);
233 
234  return KE_OK;
235 }
236 
237 int ReferFplStatus(int fplId, iop_fpl_info_t *info)
238 {
239  struct fpool *fpl;
240  int state;
241 
242  if (QueryIntrContext()) {
243  return KE_ILLEGAL_CONTEXT;
244  }
245 
246  CpuSuspendIntr(&state);
247  fpl = HANDLE_PTR(fplId);
248  if (!HANDLE_VERIFY(fplId, TAG_FPL)) {
249  CpuResumeIntr(state);
250  return KE_UNKNOWN_FPLID;
251  }
252 
253  fpl_get_info(fpl, info);
254 
255  CpuResumeIntr(state);
256 
257  return KE_OK;
258 }
259 
260 int iReferFplStatus(int fplId, iop_fpl_info_t *info)
261 {
262  struct fpool *fpl;
263 
264  if (!QueryIntrContext()) {
265  return KE_ILLEGAL_CONTEXT;
266  }
267 
268  fpl = HANDLE_PTR(fplId);
269  if (!HANDLE_VERIFY(fplId, TAG_FPL)) {
270  return KE_UNKNOWN_FPLID;
271  }
272 
273  fpl_get_info(fpl, info);
274 
275  return KE_OK;
276 }
277 
278 static struct fpl_block *fpl_block_alloc(struct fpool *fpl)
279 {
280  struct fpl_block *tail, *head;
281 
282  if (!fpl->free) {
283  return NULL;
284  }
285 
286  fpl->free_blocks--;
287 
288  tail = fpl->free;
289  head = tail->next;
290 
291  if (tail == head) {
292  fpl->free = NULL;
293  } else {
294  tail->next = head->next;
295  }
296 
297  return head;
298 }
299 
300 static void fpl_block_free(struct fpool *fpl, struct fpl_block *block)
301 {
302  struct fpl_block *tail;
303  tail = fpl->free;
304 
305  fpl->free_blocks++;
306  if (tail) {
307  block->next = tail->next;
308  tail->next = block;
309  fpl->free = block;
310  } else {
311  fpl->free = block;
312  block->next = block;
313  }
314 }
315 
316 static void fpl_get_info(struct fpool *fpl, iop_fpl_info_t *info)
317 {
318  info->attr = fpl->event.attr;
319  info->option = fpl->event.option;
320  info->blockSize = fpl->block_size;
321  info->numBlocks = fpl->blocks;
322  info->freeBlocks = fpl->free_blocks;
323  info->numWaitThreads = fpl->event.waiter_count;
324 }
s_info
Definition: xprintf.c:78
_iop_fpl_param
Definition: thfpool.h:35
thread
Definition: thcommon.h:143
QueryIntrContext
int QueryIntrContext(void)
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
fpool
Definition: thcommon.h:112
fpl_block
Definition: thcommon.h:107
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
intrman.h
_iop_fpl_info
Definition: thfpool.h:43
kerr.h