Kernel - Fixed IPC messages failing when list is emptied
[tpg/acess2.git] / Kernel / messages.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * messages.c
6  * - IPC Messages
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <threads.h>
11 #include <threads_int.h>
12 #include <errno.h>
13
14 // === IMPORTS ===
15 extern tShortSpinlock   glThreadListLock;
16
17 // === CODE ===
18 /**
19  * \fn int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
20  * \brief Send an IPC message
21  * \param Err   Pointer to the errno variable
22  * \param Dest  Destination Thread
23  * \param Length        Length of the message
24  * \param Data  Message data
25  */
26 int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
27 {
28         tThread *thread;
29         tMsg    *msg;
30         
31         ENTER("pErr iDest iLength pData", Err, Dest, Length, Data);
32         
33         if(Length <= 0 || !Data) {
34                 *Err = -EINVAL;
35                 LEAVE_RET('i', -1);
36         }
37         
38         // Get thread
39         thread = Threads_GetThread( Dest );
40         
41         // Error check
42         if(!thread)     LEAVE_RET('i', -1);
43         
44         // Get Spinlock
45         SHORTLOCK( &thread->IsLocked );
46         
47         // Check if thread is still alive
48         if(thread->Status == THREAD_STAT_DEAD) {
49                 SHORTREL( &thread->IsLocked );
50                 LEAVE_RET('i', -1);
51         }
52         
53         // Create message
54         msg = malloc( sizeof(tMsg)+Length );
55         msg->Next = NULL;
56         msg->Source = Proc_GetCurThread()->TID;
57         msg->Length = Length;
58         memcpy(msg->Data, Data, Length);
59         
60         // If there are already messages
61         if(thread->LastMessage) {
62                 thread->LastMessage->Next = msg;
63                 thread->LastMessage = msg;
64         } else {
65                 thread->Messages = msg;
66                 thread->LastMessage = msg;
67         }
68         
69         SHORTREL(&thread->IsLocked);
70         
71         SHORTLOCK(&glThreadListLock);
72         LOG("Waking %p (%i %s)", thread, thread->TID, thread->ThreadName);
73         Threads_Wake( thread );
74         SHORTREL(&glThreadListLock);
75         
76         LEAVE_RET('i', 0);
77 }
78
79 /**
80  * \fn int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
81  * \brief Gets a message
82  * \param Err   Pointer to \a errno
83  * \param Source        Where to put the source TID
84  * \param Buffer        Buffer to place the message data (set to NULL to just get message length)
85  */
86 int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
87 {
88          int    ret;
89         void    *tmp;
90         tThread *cur = Proc_GetCurThread();
91
92         ENTER("pSource pBuffer", Source, Buffer);
93         
94         // Check if queue has any items
95         if(!cur->Messages) {
96                 LEAVE('i', 0);
97                 return 0;
98         }
99
100         SHORTLOCK( &cur->IsLocked );
101         
102         if(Source) {
103                 *Source = cur->Messages->Source;
104                 LOG("*Source = %i", *Source);
105         }
106         
107         // Get message length
108         if( !Buffer ) {
109                 ret = cur->Messages->Length;
110                 SHORTREL( &cur->IsLocked );
111                 LEAVE('i', ret);
112                 return ret;
113         }
114         
115         // Get message
116         if(Buffer != GETMSG_IGNORE)
117         {
118                 if( !CheckMem( Buffer, cur->Messages->Length ) )
119                 {
120                         LOG("Invalid buffer");
121                         *Err = -EINVAL;
122                         SHORTREL( &cur->IsLocked );
123                         LEAVE('i', -1);
124                         return -1;
125                 }
126                 LOG("Copied to buffer");
127                 memcpy(Buffer, cur->Messages->Data, cur->Messages->Length);
128         }
129         ret = cur->Messages->Length;
130         
131         // Remove from list
132         tmp = cur->Messages;
133         cur->Messages = cur->Messages->Next;
134         if(cur->Messages == NULL)       cur->LastMessage = NULL;
135         
136         SHORTREL( &cur->IsLocked );
137         
138         free(tmp);      // Free outside of lock
139
140         LEAVE('i', ret);
141         return ret;
142 }

UCC git Repository :: git.ucc.asn.au