Kernel - Planning SMP fix with sleep edge case
[tpg/acess2.git] / KernelLand / Kernel / workqueue.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * workqueue.c
6  * - Worker FIFO Queue (Single Consumer, Interrupt Producer)
7  */
8 #include <acess.h>
9 #include <workqueue.h>
10 #include <threads_int.h>
11
12 #define QUEUENEXT(ptr)  (*( (void**)(ptr) + Queue->NextOffset/sizeof(void*) ))
13
14 // === CODE ===
15 void Workqueue_Init(tWorkqueue *Queue, const char *Name, size_t NextOfset)
16 {
17         Queue->Name = Name;
18         Queue->NextOffset = NextOfset;
19 }
20
21 void *Workqueue_GetWork(tWorkqueue *Queue)
22 {
23         tThread *us;
24
25         for( ;; )
26         {
27                 // Check for work
28                 SHORTLOCK(&Queue->Protector);
29                 if(Queue->Head)
30                 {
31                         void *ret = Queue->Head;
32                         Queue->Head = QUEUENEXT( ret );
33                         if(Queue->Tail == ret)
34                                 Queue->Tail = NULL;
35                         SHORTREL(&Queue->Protector);    
36                         return ret;
37                 }
38                 
39                 #if 0
40                 Threads_int_Sleep(THREAD_STAT_QUEUESLEEP,
41                         Queue, 0,
42                         &Queue->Sleeper, NULL, &Queue->Protector);
43                 #endif
44                 // Go to sleep
45                 SHORTLOCK(&glThreadListLock);
46                 us = Threads_RemActive();
47                 us->WaitPointer = Queue;
48                 us->Status = THREAD_STAT_QUEUESLEEP;
49                 Queue->Sleeper = us;
50                 
51                 SHORTREL(&Queue->Protector);    
52                 SHORTREL(&glThreadListLock);
53                 
54                 // Yield and sleep
55                 Threads_int_WaitForStatusEnd(THREAD_STAT_QUEUESLEEP);
56
57                 us->WaitPointer = NULL;
58         }
59 }
60
61 void Workqueue_AddWork(tWorkqueue *Queue, void *Ptr)
62 {
63         SHORTLOCK(&Queue->Protector);
64
65         if( Queue->Tail )
66                 QUEUENEXT(Queue->Tail) = Ptr;
67         else
68                 Queue->Head = Ptr;
69         Queue->Tail = Ptr;
70         QUEUENEXT(Ptr) = NULL;
71
72         if( Queue->Sleeper )
73         {       
74                 if( Queue->Sleeper->Status != THREAD_STAT_ACTIVE )
75                         Threads_AddActive(Queue->Sleeper);
76                 Queue->Sleeper = NULL;
77         }
78         SHORTREL(&Queue->Protector);
79 }

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