Kernel/x86 - Clean up some of the task switching code (possibly a little broken)
[tpg/acess2.git] / KernelLand / 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 #include <events.h>
14
15 // === CODE ===
16 /**
17  * \fn int Proc_SendMessage(Uint Dest, int Length, void *Data)
18  * \brief Send an IPC message
19  * \param Dest  Destination Thread
20  * \param Length        Length of the message
21  * \param Data  Message data
22  */
23 int Proc_SendMessage(Uint Dest, int Length, void *Data)
24 {
25         tThread *thread;
26         tMsg    *msg;
27         
28         ENTER("iDest iLength pData", Dest, Length, Data);
29         
30         if(Length <= 0 || !Data) {
31                 errno = -EINVAL;
32                 LEAVE_RET('i', -1);
33         }
34         
35         // TODO: Check message length against global/per-thread maximums
36         // TODO: Restrict queue length
37
38         // Get thread
39         thread = Threads_GetThread( Dest );
40         if(!thread)     LEAVE_RET('i', -1);
41         LOG("Destination %p(%i %s)", thread, thread->TID, thread->ThreadName);
42         
43         // Get Spinlock
44         SHORTLOCK( &thread->IsLocked );
45         
46         // Check if thread is still alive
47         if(thread->Status == THREAD_STAT_DEAD) {
48                 SHORTREL( &thread->IsLocked );
49                 LEAVE_RET('i', -1);
50         }
51         
52         // Create message
53         msg = malloc( sizeof(tMsg)+Length );
54         msg->Next = NULL;
55         msg->Source = Proc_GetCurThread()->TID;
56         msg->Length = Length;
57         memcpy(msg->Data, Data, Length);
58         
59         // If there are already messages
60         if(thread->LastMessage) {
61                 thread->LastMessage->Next = msg;
62                 thread->LastMessage = msg;
63         } else {
64                 thread->Messages = msg;
65                 thread->LastMessage = msg;
66         }
67         
68         SHORTREL(&thread->IsLocked);
69
70         // Wake the thread      
71         LOG("Waking %p (%i %s)", thread, thread->TID, thread->ThreadName);
72         Threads_PostEvent( thread, THREAD_EVENT_IPCMSG );
73         
74         LEAVE_RET('i', 0);
75 }
76
77 /**
78  * \fn int Proc_GetMessage(Uint *Source, void *Buffer)
79  * \brief Gets a message
80  * \param Source        Where to put the source TID
81  * \param BufSize       Size of \a Buffer, only this many bytes will be copied
82  * \param Buffer        Buffer to place the message data (set to NULL to just get message length)
83  * \return Message length
84  */
85 int Proc_GetMessage(Uint *Source, Uint BufSize, void *Buffer)
86 {
87          int    ret;
88         void    *tmp;
89         tThread *cur = Proc_GetCurThread();
90
91         ENTER("pSource xBufSize pBuffer", Source, BufSize, Buffer);
92         
93         // Check if queue has any items
94         if(!cur->Messages) {
95                 LOG("empty queue");
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, BufSize ) )
119                 {
120                         LOG("Invalid buffer");
121                         errno = -EINVAL;
122                         SHORTREL( &cur->IsLocked );
123                         LEAVE('i', -1);
124                         return -1;
125                 }
126                 if( BufSize < cur->Messages->Length )
127                         Log_Notice("Threads", "Buffer of 0x%x passed, but 0x%x long message, truncated",
128                                 BufSize, cur->Messages->Length);
129                 else if( BufSize < cur->Messages->Length )
130                         BufSize = cur->Messages->Length;
131                 else
132                         ;       // equal
133                 LOG("Copied to buffer");
134                 memcpy(Buffer, cur->Messages->Data, BufSize);
135         }
136         ret = cur->Messages->Length;
137         
138         // Remove from list
139         tmp = cur->Messages;
140         cur->Messages = cur->Messages->Next;
141         // - Removed last message? Clear the end-of-list pointer
142         if(cur->Messages == NULL)       cur->LastMessage = NULL;
143         //  > Otherwise, re-mark the IPCMSG event flag
144         else    cur->EventState |= THREAD_EVENT_IPCMSG;
145         
146         SHORTREL( &cur->IsLocked );
147
148         free(tmp);      // Free outside of lock
149
150         LEAVE('i', ret);
151         return ret;
152 }

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