root/src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.c
#include "RPCPendingCalls.h"
#include <string.h>

extern bool conf_no_check_ip_xid;

extern void 
PendingCallInit(struct PendingCall *call)
{
        call->buffer=NULL;
}

extern void 
PendingCallDestroy(struct PendingCall *call)
{
        free (call->buffer);
}

extern void 
RPCPendingCallsInit(struct RPCPendingCalls *calls)
{
        SemaphorePoolInit(&calls->fPool);
        
        calls->fFirst=NULL;
        calls->fSem=create_sem(1,"RPCPendingCalls");
        set_sem_owner (calls->fSem,B_SYSTEM_TEAM);
}

extern void 
RPCPendingCallsDestroy(struct RPCPendingCalls *calls)
{
        delete_sem(calls->fSem);
        
        while (calls->fFirst)
        {
                struct PendingCall *next=calls->fFirst->next;
                
                SemaphorePoolPut (&calls->fPool,calls->fFirst->sem);
                PendingCallDestroy (calls->fFirst);
                free (calls->fFirst);

                calls->fFirst=next;
        }
        
        SemaphorePoolDestroy (&calls->fPool);
}

extern struct PendingCall *
RPCPendingCallsAddPendingCall (struct RPCPendingCalls *calls,
                                                                int32 xid, const struct sockaddr_in *addr)
{
        struct PendingCall *call=(struct PendingCall *)malloc(sizeof(struct PendingCall));
        PendingCallInit (call);
        
        call->sem=SemaphorePoolGet(&calls->fPool);
                
        memcpy(&call->addr,addr,sizeof(struct sockaddr_in));
        call->xid=xid;

        while (acquire_sem (calls->fSem)==B_INTERRUPTED);
        
        call->next=calls->fFirst;
        calls->fFirst=call;

        while (release_sem (calls->fSem)==B_INTERRUPTED);
        
        return call;
}

extern struct PendingCall *
RPCPendingCallsFindAndRemovePendingCall (struct RPCPendingCalls *calls,
                                                                                int32 xid, const struct sockaddr_in *addr)
{
        struct PendingCall *last=NULL;
        struct PendingCall *current;
        
        while (acquire_sem (calls->fSem)==B_INTERRUPTED);
        
        current=calls->fFirst; // mmu_man
        
        while (current)
        {
                if (current->xid==xid)
                {
                        if (((current->addr.sin_addr.s_addr==addr->sin_addr.s_addr)&&
                                (current->addr.sin_port==addr->sin_port)) || conf_no_check_ip_xid)
                        {       
                                if (last)
                                        last->next=current->next;
                                else
                                        calls->fFirst=current->next;

                                current->next=NULL;                     
                                
                                while (release_sem (calls->fSem)==B_INTERRUPTED);
                                return current;
                        }
                }

                last=current;
                current=current->next;
        }
        
        while (release_sem (calls->fSem)==B_INTERRUPTED);
        
        return NULL;
}

extern void 
SemaphorePoolInit(struct SemaphorePool *pool)
{
        pool->fPool=NULL;
        pool->fPoolCount=0;
        pool->fPoolSize=0;
        
        pool->fPoolSem=create_sem(1,"semaphore_pool_sem");
        set_sem_owner (pool->fPoolSem,B_SYSTEM_TEAM);
}

extern void 
SemaphorePoolDestroy(struct SemaphorePool *pool)
{
        int32 i;
        
        for (i=0;i<pool->fPoolCount;i++)
                delete_sem (pool->fPool[i]);

        free (pool->fPool);
        
        delete_sem (pool->fPoolSem);
}

extern sem_id 
SemaphorePoolGet(struct SemaphorePool *pool)
{
        sem_id sem;
        
        while (acquire_sem(pool->fPoolSem)==B_INTERRUPTED)
        {
        }
        
        if (pool->fPoolCount==0)
        {
                sem=create_sem (0,"pending_call");
                
                while (release_sem(pool->fPoolSem)==B_INTERRUPTED)
                {
                }
                
                return sem;
        }

        sem=pool->fPool[pool->fPoolCount-1];
        pool->fPoolCount--;

        while (release_sem(pool->fPoolSem)==B_INTERRUPTED)
        {
        }
        
        return sem;
}

extern void 
SemaphorePoolPut(struct SemaphorePool *pool, sem_id sem)
{
        while (acquire_sem(pool->fPoolSem)==B_INTERRUPTED)
        {
        }

        if (pool->fPoolCount+1>pool->fPoolSize)
        {
                pool->fPoolSize+=8;
                pool->fPool=(sem_id *)realloc(pool->fPool,pool->fPoolSize*sizeof(sem_id));
        }

        pool->fPool[pool->fPoolCount]=sem;
        pool->fPoolCount++;
        
        while (release_sem(pool->fPoolSem)==B_INTERRUPTED)
        {
        }
}