threading issues

Discuss the development of software, tools, libraries and anything else that helps make ps2dev happen.

Moderators: cheriff, Herben

Post Reply
radad
Posts: 246
Joined: Wed May 19, 2004 4:54 pm
Location: Melbourne, Australia

threading issues

Post by radad »

I am working on a multithreaded app. It crashes occasionally and I not completely sure why. It seems to happen when I make an rpc call.

Are the rpc and dma modules thread safe? Can two threads make an rpc call or dma at the same time? And even if they do I assume they get queued up at the iop end.
EEUG
Posts: 136
Joined: Fri May 13, 2005 4:49 am
Location: The Netherlands

Post by EEUG »

...well, in SMS these threads are a pain in the ... Somehow they work now and I'm quite afraid to touch anything :). I would try to put semaphores to guard "critical" sections of the code...
apache37
Posts: 76
Joined: Fri Jun 04, 2004 3:13 pm

Post by apache37 »

Is there a good reference where I can learn about threads/semaphores on ps2? I would like to know if variables can be protected or locked as well as joining threads.
radad
Posts: 246
Joined: Wed May 19, 2004 4:54 pm
Location: Melbourne, Australia

Post by radad »

I found the issue, it appears that rpc calls are not thread safe, at least not if they share the same t_SifRpcClientData . Not sure about dma but I haven't any issues with it yet.

Here are the changes:

Code: Select all

Index: audsrv/include/audsrv.h
===================================================================
--- audsrv/include/audsrv.h	(revision 1232)
+++ audsrv/include/audsrv.h	(working copy)
@@ -43,6 +43,7 @@
 #define AUDSRV_ERR_NO_MORE_CHANNELS        0x0007
 
 #define AUDSRV_ERR_FAILED_TO_LOAD_ADPCM    0x0010
+#define AUDSRV_ERR_FAILED_TO_CREATE_SEMA    0x0011
 
 /** structure used to set new format */
 typedef struct audsrv_fmt_t
Index: audsrv/src/audsrv_rpc.c
===================================================================
--- audsrv/src/audsrv_rpc.c	(revision 1232)
+++ audsrv/src/audsrv_rpc.c	(working copy)
@@ -35,6 +35,7 @@
 
 static int initialized = 0;
 static int audsrv_error = AUDSRV_ERR_NOERROR;
+static int completion_sema;
 
 /* nasty forwards */
 static void fillbuf_requested(void *pkt, void *arg);
@@ -48,6 +49,11 @@
 	audsrv_error = err;
 }
 
+static void _audsrv_intr()
+{
+	iSignalSema(completion_sema);
+}
+
 /** Returns the last error audsrv raised
     @returns error code
 */
@@ -63,8 +69,10 @@
 */
 static int call_rpc_1(int func, int arg)
 {
+	WaitSema(completion_sema);
+
 	sbuff[0] = arg;
-	SifCallRpc(&cd0, func, 0, sbuff, 1*4, sbuff, 4, 0, 0);
+	SifCallRpc(&cd0, func, 0, sbuff, 1*4, sbuff, 4, _audsrv_intr, 0);
 	FlushCache(0);
 
 	set_error(sbuff[0]);
@@ -79,9 +87,11 @@
 */
 static int call_rpc_2(int func, int arg1, int arg2)
 {
+	WaitSema(completion_sema);
+
 	sbuff[0] = arg1;
 	sbuff[1] = arg2;
-	SifCallRpc(&cd0, func, 0, sbuff, 2*4, sbuff, 4, 0, 0);
+	SifCallRpc(&cd0, func, 0, sbuff, 2*4, sbuff, 4, _audsrv_intr, 0);
 	FlushCache(0);
 
 	set_error(sbuff[0]);
@@ -93,7 +103,9 @@
 */
 int audsrv_quit()
 {
-	SifCallRpc(&cd0, AUDSRV_QUIT, 0, sbuff, 1*4, sbuff, 4, 0, 0);
+	WaitSema(completion_sema);
+
+	SifCallRpc(&cd0, AUDSRV_QUIT, 0, sbuff, 1*4, sbuff, 4, _audsrv_intr, 0);
 	set_error(AUDSRV_ERR_NOERROR);
 	return 0;
 }
@@ -109,10 +121,12 @@
 */
 int audsrv_set_format(struct audsrv_fmt_t *fmt)
 {
+	WaitSema(completion_sema);
+
 	sbuff[0] = fmt->freq;
 	sbuff[1] = fmt->bits;
 	sbuff[2] = fmt->channels;
-	SifCallRpc(&cd0, AUDSRV_SET_FORMAT, 0, sbuff, 3*4, sbuff, 4, 0, 0);
+	SifCallRpc(&cd0, AUDSRV_SET_FORMAT, 0, sbuff, 3*4, sbuff, 4, _audsrv_intr, 0);
 	FlushCache(0);
 	set_error(sbuff[0]);
 	return sbuff[0];
@@ -268,11 +282,13 @@
 	maxcopy = sizeof(sbuff) - sizeof(int);
 	while (bytes > 0)
 	{
+		WaitSema(completion_sema);
+
 		copy = MIN(bytes, maxcopy);
 		sbuff[0] = copy;
 		memcpy(&sbuff[1], chunk, copy);
 		packet_size = copy + sizeof(int);
-		SifCallRpc(&cd0, AUDSRV_PLAY_AUDIO, 0, sbuff, packet_size, sbuff, 1*4, 0, 0);
+		SifCallRpc(&cd0, AUDSRV_PLAY_AUDIO, 0, sbuff, packet_size, sbuff, 1*4, _audsrv_intr, 0);
 		FlushCache(0);
 
 		if &#40;sbuff&#91;0&#93; < 0&#41;
@@ -331,6 +347,12 @@
 		nopdelay&#40;&#41;;
 	&#125;
 
+	ee_sema_t compSema;
+	compSema.init_count = 1;
+	compSema.max_count = 1;
+	compSema.option = 0;
+	completion_sema = CreateSema&#40;&compSema&#41;;
+
 	SifCallRpc&#40;&cd0, AUDSRV_INIT, 0, sbuff, 64, sbuff, 64, 0, 0&#41;;
 	FlushCache&#40;0&#41;;
 	ret = sbuff&#91;0&#93;;
@@ -374,6 +396,8 @@
 	SifDmaTransfer_t sifdma;
 	int id;
 
+	WaitSema&#40;completion_sema&#41;;
+
 	iop_addr = SifAllocIopHeap&#40;size&#41;;
 	if &#40;iop_addr == 0&#41;
 	&#123;
@@ -393,7 +417,7 @@
 	sbuff&#91;1&#93; = size;
 	sbuff&#91;2&#93; = &#40;int&#41;adpcm; /* use as id */
 
-	SifCallRpc&#40;&cd0, AUDSRV_LOAD_ADPCM, 0, sbuff, 12, sbuff, 16, 0, 0&#41;;
+	SifCallRpc&#40;&cd0, AUDSRV_LOAD_ADPCM, 0, sbuff, 12, sbuff, 16, _audsrv_intr, 0&#41;;
 	SifFreeIopHeap&#40;iop_addr&#41;;
 
 	if&#40;sbuff&#91;0&#93; != 0&#41; 
radad
Posts: 246
Joined: Wed May 19, 2004 4:54 pm
Location: Melbourne, Australia

Post by radad »

apache37 wrote:Is there a good reference where I can learn about threads/semaphores on ps2? I would like to know if variables can be protected or locked as well as joining threads.
There is only one synchronisation object on the PS2, they call it a sema. It is a basic atomic increment/decrement object with a wait state when it reaches zero.

You can use it like a traditional simple mutex. Simple meaning it doesn't support recursive locking.

You can use it like a traditional simple semaphore. Simple meaning only one waiting thread will wake up. Also if no thread is currently waiting then the next thread to wait will wake up immediately.

You can also use it build up more complex mutexes. One which support recursive locking.

Or to buid up complex semaphores. Ones which can wake all waiting threads. And only wake currently waiting threads.

Lastly there is no direct support for thread joining. You can build your own from this basic sema though. Just get the thread to signal the sema when it exits.
apache37
Posts: 76
Joined: Fri Jun 04, 2004 3:13 pm

Post by apache37 »

Than you for the response. I think I can achieve what I need with simple threads for now.

Also is there a way to kill all threads in the ps2 even if I didnt start them?
Post Reply