Kernel - (experimental) Allowing THREAD_EVENT_TIMER to wake a semaphore
authorJohn Hodge <[email protected]>
Mon, 28 Jan 2013 10:56:20 +0000 (18:56 +0800)
committerJohn Hodge <[email protected]>
Mon, 28 Jan 2013 10:56:20 +0000 (18:56 +0800)
KernelLand/Kernel/events.c
KernelLand/Kernel/include/threads_int.h
KernelLand/Kernel/semaphore.c
KernelLand/Modules/IPStack/arp.c

index da095e9..c3ab282 100644 (file)
@@ -26,15 +26,25 @@ void Threads_PostEvent(tThread *Thread, Uint32 EventMask)
        LOG("Thread->EventState = 0x%x", Thread->EventState);
        
        // Currently sleeping on an event?
-       if( Thread->Status == THREAD_STAT_EVENTSLEEP )
+       switch(Thread->Status)
        {
-               // Waiting on this event?
+       // Waiting on this event?
+       case THREAD_STAT_EVENTSLEEP:
                if( (Uint32)Thread->RetStatus & EventMask )
                {
                        // Wake up
                        LOG("Waking thread %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
                        Threads_AddActive(Thread);
                }
+               break;
+       case THREAD_STAT_SEMAPHORESLEEP:
+               if( EventMask & THREAD_EVENT_TIMER )
+               {
+                       LOG("Waking %p(%i %s) from semaphore on timer",
+                               Thread, Thread->TID, Thread->ThreadName);
+                       Semaphore_ForceWake(Thread);
+               }
+               break;
        }
        
        SHORTREL( &Thread->IsLocked );
index 4845264..642f6c3 100644 (file)
@@ -152,4 +152,6 @@ extern tThread      *Threads_GetNextToRun(int CPU, tThread *Last);
 extern tThread *Threads_CloneTCB(Uint Flags);
 extern tThread *Threads_CloneThreadZero(void);
 
+extern void    Semaphore_ForceWake(tThread *Thread);
+
 #endif
index 2c9fc94..ce7d4ba 100644 (file)
@@ -78,6 +78,7 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
                
                SHORTREL( &Sem->Protector );    // Release first to make sure it is released
                SHORTREL( &glThreadListLock );
+               // Sleep until woken (either by getting what we need, or a timer event)
                while( us->Status == THREAD_STAT_SEMAPHORESLEEP )
                {
                        Threads_Yield();
@@ -244,13 +245,44 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
                if( toWake->Status != THREAD_STAT_ACTIVE )
                        Threads_AddActive(toWake);
                else
-                       Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName);
+                       Warning("Thread %p (%i %s) is already awake",
+                               toWake, toWake->TID, toWake->ThreadName);
        }
        SHORTREL( &Sem->Protector );
        
        return added;
 }
 
+void Semaphore_ForceWake(tThread *Thread)
+{
+       if( !CPU_HAS_LOCK(&Thread->IsLocked) ) {
+               Log_Error("Semaphore", "Force wake should be called with the thread lock held");
+               return ;
+       }
+       if( Thread->Status != THREAD_STAT_SEMAPHORESLEEP ) {
+               Log_Error("Semaphore", "_ForceWake called on non-semaphore thread");
+               return ;
+       }
+
+       tSemaphore *sem = Thread->WaitPointer;
+       SHORTLOCK( &sem->Protector );
+       tThread *prev = NULL;
+       if( sem->Waiting == Thread )
+               sem->Waiting = sem->Waiting->Next;
+       else
+       {
+               for( prev = sem->Waiting; prev && prev->Next != Thread; prev = prev->Next )
+                       ;
+               if( prev )
+                       prev->Next = Thread->Next;
+       }
+       if( sem->LastWaiting == Thread )
+               sem->LastWaiting = prev;
+       SHORTREL( &sem->Protector );
+       Thread->RetStatus = 0;
+       Threads_AddActive(Thread);
+}
+
 //
 // Get the current value of a semaphore
 //
index e152e33..43c3425 100644 (file)
@@ -9,9 +9,11 @@
 #include "link.h"
 #include "ipv4.h"      // For IPv4_Netmask
 #include "include/adapters_int.h"      // for MAC addr
+#include <semaphore.h>
+#include <timers.h>
 
 #define ARPv6  0
-#define        ARP_CACHE_SIZE  64
+#define        ARP_CACHE_SIZE  128
 #define        ARP_MAX_AGE             (60*60*1000)    // 1Hr
 
 // === IMPORTS ===
@@ -34,6 +36,8 @@ struct sARP_Cache4 {
 }      *gaARP_Cache4;
  int   giARP_Cache4Space;
 tMutex glARP_Cache4;
+tSemaphore     gARP_Cache4Semaphore;
+ int   giARP_WaitingThreads;
 #if ARPv6
 struct sARP_Cache6 {
        tIPv6   IP;
@@ -44,7 +48,6 @@ struct sARP_Cache6 {
  int   giARP_Cache6Space;
 tMutex glARP_Cache6;
 #endif
-volatile int   giARP_LastUpdateID = 0;
 
 // === CODE ===
 /**
@@ -72,10 +75,8 @@ int ARP_Initialise()
  */
 tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
 {
-        int    lastID;
         int    i;
        struct sArpRequest4     req;
-       Sint64  timeout;
        
        ENTER("pInterface xAddress", Interface, Address);
        
@@ -133,10 +134,9 @@ tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
                LEAVE('-');
                return gaARP_Cache4[i].MAC;
        }
+       giARP_WaitingThreads ++;
        Mutex_Release( &glARP_Cache4 );
        
-       lastID = giARP_LastUpdateID;
-       
        // Create request
        Log_Log("ARP4", "Asking for address %i.%i.%i.%i",
                Address.B[0], Address.B[1], Address.B[2], Address.B[3]
@@ -151,35 +151,33 @@ tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
        req.DestMac = cMAC_BROADCAST;
        req.DestIP = Address;
 
-       tIPStackBuffer  *buffer = IPStack_Buffer_CreateBuffer(3);       // Assumes only a header and footer at link layer
+       // Assumes only a header and footer at link layer
+       tIPStackBuffer  *buffer = IPStack_Buffer_CreateBuffer(3);
        IPStack_Buffer_AppendSubBuffer(buffer, sizeof(struct sArpRequest4), 0, &req, NULL, NULL);
 
        // Send Request
        Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, buffer);
 
+       // Clean up
        IPStack_Buffer_DestroyBuffer(buffer);
        
-       timeout = now() + Interface->TimeoutDelay;
-       
        // Wait for a reply
+       Time_ScheduleTimer(NULL, Interface->TimeoutDelay);
        for(;;)
        {
-               while(lastID == giARP_LastUpdateID && now() < timeout) {
-                       Threads_Yield();
-               }
-               
-               if( now() >= timeout ) {
+               if( Semaphore_Wait(&gARP_Cache4Semaphore, 1) != 1 )
+               {
+                       giARP_WaitingThreads --;
                        Log_Log("ARP4", "Timeout");
-                       break;  // Timeout
+                       break;
                }
                
-               lastID = giARP_LastUpdateID;
-               
                Mutex_Acquire( &glARP_Cache4 );
                for( i = 0; i < giARP_Cache4Space; i++ )
                {
                        if(gaARP_Cache4[i].IP.L != Address.L)   continue;
                        
+                       giARP_WaitingThreads --;
                        Mutex_Release( &glARP_Cache4 );
                        Log_Debug("ARP4", "Return %02x:%02x:%02x:%02x:%02x:%02x",
                                gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1], 
@@ -231,7 +229,7 @@ void ARP_UpdateCache4(tIPv4 SWAddr, tMacAddr HWAddr)
        gaARP_Cache4[i].IP = SWAddr;
        gaARP_Cache4[i].MAC = HWAddr;
        gaARP_Cache4[i].LastUpdate = now();
-       giARP_LastUpdateID ++;
+       Semaphore_Signal(&gARP_Cache4Semaphore, giARP_WaitingThreads);
        Mutex_Release(&glARP_Cache4);
 }
 

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