ps2sdk  1.1
A collection of Open Source libraries used for developing applications on Sony's PlayStation 2® (PS2).
sys_arch.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 
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <kernel.h>
15 #include <time.h>
16 #include <limits.h>
17 
18 #include "lwip/sys.h"
19 #include "lwip/opt.h"
20 #include "lwip/stats.h"
21 #include "lwip/debug.h"
22 #include "lwip/pbuf.h"
23 #include "arch/sys_arch.h"
24 
25 #include "ps2ip_internal.h"
26 
29 
30 /* Function prototypes */
31 static inline arch_message *alloc_msg(void);
32 static void free_msg(arch_message *msg);
33 static int WaitSemaTimeout(int sema, unsigned int msec);
34 
35 static int MsgCountSema;
36 
37 extern void *_gp;
38 
39 static inline arch_message *try_alloc_msg(void)
40 {
41  arch_message *message;
42 
44  {
45  DI();
46 
47  message = free_head;
49 
50  EI();
51  }else message=NULL;
52 
53  return message;
54 }
55 
56 static inline arch_message *alloc_msg(void)
57 {
58  arch_message *message;
59 
61  DI();
62 
63  message = free_head;
65 
66  EI();
67 
68  return message;
69 }
70 
71 static void free_msg(arch_message *msg)
72 {
73  DI();
74 
75  msg->next = free_head;
76  free_head = msg;
77 
78  EI();
80 }
81 
82 static void TimeoutHandler(s32 alarm_id, u16 time, void *pvArg){
83  iReleaseWaitThread((int)pvArg);
84  ExitHandler();
85 }
86 
87 static inline u32_t ComputeTimeDiff(u32 start, u32 end)
88 {
89  u32 NumTicksElasped=(end<start)?UINT_MAX-start+end:start-end;
90 
91  return(NumTicksElasped/295000);
92 }
93 
94 //Create a new thread.
95 sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
96 {
97  ee_thread_t thp;
98  int tid, rv;
99 
100  thp.attr = 0;
101  thp.option = 0;
102  thp.func = thread;
103  thp.stack_size = stacksize;
104  thp.stack = malloc(stacksize);
105  thp.initial_priority = prio;
106  thp.gp_reg = &_gp;
107 
108  if((tid = CreateThread(&thp)) < 0)
109  {
110  dbgprintf("sys_thread_new: CreateThread failed, EC: %d\n", tid);
111  return ERR_MEM;
112  }
113 
114  if((rv = StartThread(tid, arg)) < 0)
115  {
116  dbgprintf("sys_thread_new: StartThread failed, EC: %d\n", rv);
117  DeleteThread(tid);
118  return ERR_MEM;
119  }
120 
121  dbgprintf("sys_thread_new(): %d\n", tid);
122 
123  return((sys_thread_t)tid);
124 }
125 
126 err_t sys_mbox_new(sys_mbox_t *mbox, int size)
127 {
128  struct MboxData *MBox;
129  ee_sema_t sema;
130 
131  *mbox=SYS_MBOX_NULL;
132 
133  if((MBox=malloc(sizeof(struct MboxData)))!=NULL)
134  {
135  //Last = first, empty mbox.
136  MBox->LastMessage=MBox->FirstMessage=NULL;
137 
138  sema.attr = 0;
139  sema.option = (u32)"PS2IP-msgcount";
140  sema.init_count=0;
142  if((MBox->MessageCountSema=CreateSema(&sema))<0)
143  {
144  printf("sys_mbox_new: CreateMbx failed. Code: %d\n", MBox->MessageCountSema);
145  free(MBox);
146  return ERR_MEM;
147  }
148  }
149  else{
150  printf("sys_mbox_new: Out of memory.\n");
151  return ERR_MEM;
152  }
153 
154  dbgprintf("sys_mbox_new(): sema %d\n", MBox->MessageCountSema);
155 
156  *mbox=MBox;
157 
158  return ERR_OK;
159 }
160 
161 //Delete the messagebox, (*pMBox).
162 void sys_mbox_free(sys_mbox_t *pMBox)
163 {
164  arch_message *Message, *NextMessage;
165 
166  /* Free all messages that were not freed yet. */
167  Message=(*pMBox)->FirstMessage;
168  while(Message!=NULL)
169  {
170  NextMessage=Message->next;
171  free_msg(Message);
172  Message=NextMessage;
173  }
174 
175  /* Delete all allocated resources for this message box and mark the message box as invalid. */
176  DeleteSema((*pMBox)->MessageCountSema);
177  free((*pMBox));
178  (*pMBox)=SYS_MBOX_NULL;
179 }
180 
181 int sys_mbox_valid(sys_mbox_t *mbox)
182 {
183  return((*mbox)!=SYS_MBOX_NULL);
184 }
185 
186 void sys_mbox_set_invalid(sys_mbox_t *mbox)
187 {
188  *mbox=SYS_MBOX_NULL;
189 }
190 
191 extern unsigned short int hsyncTicksPerMSec;
192 
193 static inline unsigned int mSec2HSyncTicks(unsigned int msec)
194 {
195  return msec*hsyncTicksPerMSec;
196 }
197 
198 static void RetrieveMbxInternal(sys_mbox_t mBox, arch_message **message)
199 {
200  arch_message *NextMessage;
201 
202  DI();
203 
204  *message=mBox->FirstMessage; //Take first message in mbox
205 
206  //The next message is next. If there is no next message, NULL is assigned,
207  NextMessage=(unsigned int)(*message)->next!=0xFFFFFFFF?(*message)->next:NULL;
208 
209  //if the mbox only had one message, then update LastMessage as well.
210  if(mBox->FirstMessage == mBox->LastMessage)
211  mBox->LastMessage = NULL;
212 
213  mBox->FirstMessage = NextMessage; //The next message becomes the first message. Or NULL, if there are no next messages.
214 
215  EI();
216 }
217 
218 static int WaitSemaTimeout(int sema, unsigned int msec)
219 {
220  unsigned int ticks;
221  unsigned short int ticksToWait;
222  int alarmID, threadID;
223 
224  ticks = mSec2HSyncTicks(msec);
225  threadID = GetThreadId();
226  while(ticks > 0)
227  {
228  ticksToWait = ticks > USHRT_MAX ? USHRT_MAX : ticks;
229  alarmID = SetAlarm(ticksToWait, &TimeoutHandler, (void*)threadID);
230  if (WaitSema(sema) == sema)
231  {
232  ReleaseAlarm(alarmID);
233  return sema; //Wait condition satisfied.
234  }
235 
236  //Otherwise, continue waiting.
237  ticks -= ticksToWait;
238  }
239 
240  return -1; //Timed out.
241 }
242 
243 static int ReceiveMbx(arch_message **message, sys_mbox_t mBox, u32_t timeout)
244 {
245  int result;
246 
247  if(timeout > 0) {
248  result = WaitSemaTimeout(mBox->MessageCountSema, timeout);
249  } else {
250  result = WaitSema(mBox->MessageCountSema);
251  }
252 
253  if(result == mBox->MessageCountSema)
254  {
255  RetrieveMbxInternal(mBox, message);
256  result=0;
257  }
258  else result=-1;
259 
260  return result;
261 }
262 
263 static int PollMbx(arch_message **message, sys_mbox_t mBox)
264 {
265  int result;
266 
267  if(PollSema(mBox->MessageCountSema)==mBox->MessageCountSema)
268  {
269  RetrieveMbxInternal(mBox, message);
270  result=0;
271  }
272  else result=-1;
273 
274  return result;
275 }
276 
277 static u32_t sys_arch_mbox_fetch_internal(sys_mbox_t pMBox, void** ppvMSG, u32_t u32Timeout, char block)
278 {
279  arch_message *pmsg;
280  unsigned int TimeElasped, start;
281  int result;
282 
283  TimeElasped=0;
284  if(block){
285  start=clock()/(CLOCKS_PER_SEC/1000);
286 
287  if((result=ReceiveMbx(&pmsg, pMBox, u32Timeout))==0){
288  TimeElasped = ComputeTimeDiff(start, clock()/(CLOCKS_PER_SEC/1000));
289  }
290  else{
291  return SYS_ARCH_TIMEOUT;
292  }
293  }
294  else{
295  TimeElasped=((result=PollMbx(&pmsg, pMBox))!=0)?SYS_MBOX_EMPTY:0;
296  }
297 
298  if(result==0){
299  if(ppvMSG!=NULL) *ppvMSG = pmsg->sys_msg;
300  free_msg(pmsg);
301  }
302 
303  //Return the number of msec waited.
304  return TimeElasped;
305 }
306 
307 u32_t sys_arch_mbox_fetch(sys_mbox_t *pMBox, void** ppvMSG, u32_t u32Timeout)
308 {
309  return sys_arch_mbox_fetch_internal(*pMBox, ppvMSG, u32Timeout, 1);
310 }
311 
312 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *pMBox, void** ppvMSG)
313 {
314  return sys_arch_mbox_fetch_internal(*pMBox, ppvMSG, 0, 0);
315 }
316 
317 static void SendMbx(sys_mbox_t *mbox, arch_message *msg, void *sys_msg){
318  DI();
319 
320  /* Store the message and update the message chain for this message box. */
321  msg->sys_msg = sys_msg;
322  msg->next = NULL;
323  if((*mbox)->FirstMessage==NULL) (*mbox)->FirstMessage=msg; //If this is the first message, it goes at the front.
324  if((*mbox)->LastMessage!=NULL) (*mbox)->LastMessage->next=msg; //Otherwise, it becomes the next message of the last message.
325  (*mbox)->LastMessage=msg; //The message becomes the new message at the end of the queue.
326 
327  EI();
328  SignalSema((*mbox)->MessageCountSema);
329 }
330 
331 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *sys_msg)
332 {
333  arch_message *msg;
334  err_t result;
335 
336  /* Attempt to allocate one more message. */
337  if((msg=try_alloc_msg())!=NULL){
338  SendMbx(mbox, msg, sys_msg);
339 
340  result=ERR_OK;
341  }
342  else result=ERR_MEM;
343 
344  return result;
345 }
346 
347 void sys_mbox_post(sys_mbox_t *mbox, void *sys_msg)
348 {
349  SendMbx(mbox, alloc_msg(), sys_msg);
350 }
351 
353 {
354  //Create a new semaphore.
355  ee_sema_t sema;
356 
357  sema.init_count = count;
358  sema.max_count = 1;
359  sema.attr = 0;
360  sema.option = (u32)"PS2IP";
361 
362  if((*sem=CreateSema(&sema))<0)
363  {
364  printf("sys_sem_new: CreateSema failed, EC: %d\n", *sem);
365  return ERR_MEM;
366  }
367 
368  dbgprintf("sys_sem_new: CreateSema (CNT: %d) %d\n", count, *sem);
369 
370  return ERR_OK;
371 }
372 
374 {
375  u32_t result;
376 
377  //Wait timeout msec for the Sema to receive a signal.
378  if(timeout==0)
379  {
380  //Wait with no timeouts.
381  result=(WaitSema(*sema)==*sema?0:SYS_ARCH_TIMEOUT);
382  }
383  else if(timeout==1)
384  {
385  //Poll.
386  result=(PollSema(*sema)==*sema?0:SYS_ARCH_TIMEOUT);
387  }
388  else
389  {
390  //Use alarm to timeout.
391  unsigned int start;
392  u32_t WaitTime;
393 
394  start=clock()/(CLOCKS_PER_SEC/1000);
395  if(WaitSemaTimeout(*sema, timeout) == *sema)
396  {
397  WaitTime=ComputeTimeDiff(start, clock()/(CLOCKS_PER_SEC/1000));
398  result=(WaitTime <= timeout ? WaitTime : timeout);
399  }
400  else result=SYS_ARCH_TIMEOUT;
401  }
402 
403  return result;
404 }
405 
407 {
408  SignalSema(*Sema);
409 }
410 
412 {
413  DeleteSema(*Sema);
414 }
415 
417  return(*sem>=0);
418 }
419 
421  *sem=SYS_SEM_NULL;
422 }
423 
424 void sys_init(void)
425 {
426  arch_message *prev;
427  unsigned int i;
428  ee_sema_t sema;
429 
430  dbgprintf("sys_init: Initializing...\n");
431 
432  sema.attr = 0;
433  sema.option = (u32)"PS2IP";
434  sema.init_count = sema.max_count = SYS_MAX_MESSAGES;
435  MsgCountSema=CreateSema(&sema);
436 
437  free_head = &msg_pool[0];
438  prev = &msg_pool[0];
439 
440  for(i = 1; i < SYS_MAX_MESSAGES; i++)
441  {
442  prev->next = &msg_pool[i];
443  prev = &msg_pool[i];
444  }
445 
446  //NULL-terminate free message list
447  prev->next = NULL;
448 }
449 
451 {
452  return(clock()/(CLOCKS_PER_SEC/1000));
453 }
454 
456 {
457  return DIntr();
458 }
459 
461 {
462  if(level)
463  EIntr();
464 }
465 
466 void *ps2ip_calloc64(size_t n, size_t size)
467 {
468  void *ptr = NULL;
469  size_t sz = n * size;
470 
471  if ((ptr = memalign(64, sz)) == NULL)
472  return ptr;
473 
474  memset(ptr, 0, sz);
475  return ptr;
476 }
unsigned int u32_t
Definition: cc.h:11
unsigned char u8_t
Definition: cc.h:7
s32 CreateSema(ee_sema_t *sema)
#define ExitHandler()
Definition: kernel.h:28
s32 SignalSema(s32 sema_id)
s32 DeleteSema(s32 sema_id)
s32 CreateThread(ee_thread_t *thread)
s32 iReleaseWaitThread(s32 thread_id)
s32 PollSema(s32 sema_id)
s32 WaitSema(s32 sema_id)
s32 StartThread(s32 thread_id, void *args)
#define DI
Definition: kernel.h:24
#define EI
Definition: kernel.h:25
int DIntr(void)
s32 DeleteThread(s32 thread_id)
s32 SetAlarm(u16 time, void(*callback)(s32 alarm_id, u16 time, void *common), void *common)
s32 ReleaseAlarm(s32 alarm_id)
Definition: alarm.c:110
int EIntr(void)
s32 GetThreadId(void)
u32 time
Definition: libmouse.c:37
int sem
Definition: ps2cam_rpc.c:32
#define dbgprintf(args...)
s32 result
Definition: rpc_client.c:23
int MessageCountSema
Definition: sys_arch.h:19
arch_message * FirstMessage
Definition: sys_arch.h:20
arch_message * LastMessage
Definition: sys_arch.h:21
void * sys_msg
Definition: sys_arch.h:15
struct st_arch_message * next
Definition: sys_arch.h:14
int init_count
Definition: kernel.h:218
int max_count
Definition: kernel.h:217
u32 option
Definition: kernel.h:221
u32 attr
Definition: kernel.h:220
void * gp_reg
Definition: kernel.h:230
u32 option
Definition: kernel.h:234
int stack_size
Definition: kernel.h:229
void * func
Definition: kernel.h:227
void * stack
Definition: kernel.h:228
u32 attr
Definition: kernel.h:233
int initial_priority
Definition: kernel.h:231
static int WaitSemaTimeout(int sema, unsigned int msec)
Definition: sys_arch.c:218
int sys_sem_valid(sys_sem_t *sem)
Definition: sys_arch.c:416
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
Definition: sys_arch.c:95
u32_t sys_now(void)
Definition: sys_arch.c:450
static arch_message * free_head
Definition: sys_arch.c:28
static u32_t ComputeTimeDiff(u32 start, u32 end)
Definition: sys_arch.c:87
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *pMBox, void **ppvMSG)
Definition: sys_arch.c:312
static int ReceiveMbx(arch_message **message, sys_mbox_t mBox, u32_t timeout)
Definition: sys_arch.c:243
static arch_message * alloc_msg(void)
Definition: sys_arch.c:56
void sys_sem_set_invalid(sys_sem_t *sem)
Definition: sys_arch.c:420
void * ps2ip_calloc64(size_t n, size_t size)
Definition: sys_arch.c:466
void sys_mbox_set_invalid(sys_mbox_t *mbox)
Definition: sys_arch.c:186
static unsigned int mSec2HSyncTicks(unsigned int msec)
Definition: sys_arch.c:193
static void free_msg(arch_message *msg)
Definition: sys_arch.c:71
static int MsgCountSema
Definition: sys_arch.c:35
void sys_mbox_post(sys_mbox_t *mbox, void *sys_msg)
Definition: sys_arch.c:347
sys_prot_t sys_arch_protect(void)
Definition: sys_arch.c:455
u32_t sys_arch_mbox_fetch(sys_mbox_t *pMBox, void **ppvMSG, u32_t u32Timeout)
Definition: sys_arch.c:307
void sys_sem_free(sys_sem_t *Sema)
Definition: sys_arch.c:411
static u32_t sys_arch_mbox_fetch_internal(sys_mbox_t pMBox, void **ppvMSG, u32_t u32Timeout, char block)
Definition: sys_arch.c:277
void sys_mbox_free(sys_mbox_t *pMBox)
Definition: sys_arch.c:162
int sys_mbox_valid(sys_mbox_t *mbox)
Definition: sys_arch.c:181
static void RetrieveMbxInternal(sys_mbox_t mBox, arch_message **message)
Definition: sys_arch.c:198
static void TimeoutHandler(s32 alarm_id, u16 time, void *pvArg)
Definition: sys_arch.c:82
void sys_sem_signal(sys_sem_t *Sema)
Definition: sys_arch.c:406
void * _gp
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Definition: sys_arch.c:126
static arch_message * try_alloc_msg(void)
Definition: sys_arch.c:39
static int PollMbx(arch_message **message, sys_mbox_t mBox)
Definition: sys_arch.c:263
static void SendMbx(sys_mbox_t *mbox, arch_message *msg, void *sys_msg)
Definition: sys_arch.c:317
unsigned short int hsyncTicksPerMSec
Definition: ps2ip.c:39
u32_t sys_arch_sem_wait(sys_sem_t *sema, u32_t timeout)
Definition: sys_arch.c:373
void sys_init(void)
Definition: sys_arch.c:424
static arch_message msg_pool[SYS_MAX_MESSAGES]
Definition: sys_arch.c:27
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition: sys_arch.c:352
void sys_arch_unprotect(sys_prot_t level)
Definition: sys_arch.c:460
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *sys_msg)
Definition: sys_arch.c:331
int sys_prot_t
Definition: sys_arch.h:24
#define SYS_MBOX_NULL
Definition: sys_arch.h:7
int sys_sem_t
Definition: sys_arch.h:25
int sys_thread_t
Definition: sys_arch.h:27
#define SYS_SEM_NULL
Definition: sys_arch.h:8
#define SYS_MAX_MESSAGES
Definition: sys_arch.h:10
#define NULL
Definition: tamtypes.h:91
signed int s32
Definition: tamtypes.h:58
unsigned int u32
Definition: tamtypes.h:30
unsigned short u16
Definition: tamtypes.h:24
signed char err_t
Definition: tcpip.h:95