Page 1 of 1

threading issues

Posted: Sun Nov 13, 2005 5:21 pm
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.

Posted: Mon Nov 14, 2005 5:28 am
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...

Posted: Mon Nov 14, 2005 7:50 am
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.

Posted: Tue Nov 15, 2005 9:19 am
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; 

Posted: Tue Nov 15, 2005 10:21 am
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.

Posted: Tue Nov 15, 2005 6:03 pm
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?