#include "list.h"
#include "pipe.h"
#include "fs.h"
#include "alloc.h"
#include "fifobuffer.h"
static List* gPipeList = NULL;
static FileSystemNode* gPipesRoot = NULL;
static FileSystemDirent gDirent;
typedef struct Pipe {
char name[32];
FifoBuffer* buffer;
FileSystemNode* fsNode;
List* accessingThreads;
} Pipe;
static BOOL pipes_open(File *file, uint32 flags);
static FileSystemDirent *pipes_readdir(FileSystemNode *node, uint32 index);
static FileSystemNode *pipes_finddir(FileSystemNode *node, char *name);
void initializePipes() {
gPipeList = List_Create();
gPipesRoot = getFileSystemNode("/system/pipes");
if (NULL == gPipesRoot) {
WARNING("/system/pipes not found!!");
}
else {
gPipesRoot->open = pipes_open;
gPipesRoot->finddir = pipes_finddir;
gPipesRoot->readdir = pipes_readdir;
}
}
static BOOL pipes_open(File *file, uint32 flags) {
return TRUE;
}
static FileSystemDirent *pipes_readdir(FileSystemNode *node, uint32 index) {
int counter = 0;
List_Foreach (n, gPipeList) {
Pipe* p = (Pipe*)n->data;
if (counter == index) {
strcpy(gDirent.name, p->name);
gDirent.fileType = FT_Pipe;
return &gDirent;
}
++counter;
}
return NULL;
}
static FileSystemNode *pipes_finddir(FileSystemNode *node, char *name) {
List_Foreach (n, gPipeList) {
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0) {
return p->fsNode;
}
}
return NULL;
}
static BOOL pipe_open(File *file, uint32 flags) {
beginCriticalSection();
Pipe* pipe = file->node->privateNodeData;
List_Append(pipe->accessingThreads, file->thread);
endCriticalSection();
return TRUE;
}
static void pipe_close(File *file) {
beginCriticalSection();
Pipe* pipe = file->node->privateNodeData;
List_RemoveFirstOccurrence(pipe->accessingThreads, file->thread);
endCriticalSection();
}
static void blockAccessingThreads(Pipe* pipe) {
disableInterrupts();
List_Foreach (n, pipe->accessingThreads) {
Thread* reader = n->data;
reader->state = TS_WAITIO;
reader->state_privateData = pipe;
}
enableInterrupts();
halt();
}
static void wakeupAccessingThreads(Pipe* pipe) {
beginCriticalSection();
List_Foreach (n, pipe->accessingThreads) {
Thread* reader = n->data;
if (reader->state == TS_WAITIO) {
if (reader->state_privateData == pipe) {
reader->state = TS_RUN;
}
}
}
endCriticalSection();
}
static int32 pipe_read(File *file, uint32 size, uint8 *buffer) {
if (0 == size || NULL == buffer) {
return -1;
}
Pipe* pipe = file->node->privateNodeData;
uint32 used = 0;
while ((used = FifoBuffer_getSize(pipe->buffer)) < size) {
blockAccessingThreads(pipe);
}
disableInterrupts();
int32 readBytes = FifoBuffer_dequeue(pipe->buffer, buffer, size);
wakeupAccessingThreads(pipe);
return readBytes;
}
static int32 pipe_write(File *file, uint32 size, uint8 *buffer) {
if (0 == size || NULL == buffer) {
return -1;
}
Pipe* pipe = file->node->privateNodeData;
uint32 free = 0;
while ((free = FifoBuffer_getFree(pipe->buffer)) < size) {
blockAccessingThreads(pipe);
}
disableInterrupts();
int32 bytesWritten = FifoBuffer_enqueue(pipe->buffer, buffer, size);
wakeupAccessingThreads(pipe);
return bytesWritten;
}
BOOL createPipe(const char* name, uint32 bufferSize) {
List_Foreach (n, gPipeList) {
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0) {
return FALSE;
}
}
Pipe* pipe = (Pipe*)kmalloc(sizeof(Pipe));
memset((uint8*)pipe, 0, sizeof(Pipe));
strcpy(pipe->name, name);
pipe->buffer = FifoBuffer_create(bufferSize);
pipe->accessingThreads = List_Create();
pipe->fsNode = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
memset((uint8*)pipe->fsNode, 0, sizeof(FileSystemNode));
pipe->fsNode->privateNodeData = pipe;
pipe->fsNode->open = pipe_open;
pipe->fsNode->close = pipe_close;
pipe->fsNode->read = pipe_read;
pipe->fsNode->write = pipe_write;
List_Append(gPipeList, pipe);
return TRUE;
}
BOOL destroyPipe(const char* name) {
List_Foreach (n, gPipeList) {
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0) {
List_RemoveFirstOccurrence(gPipeList, p);
FifoBuffer_destroy(p->buffer);
List_Destroy(p->accessingThreads);
kfree(p->fsNode);
kfree(p);
return TRUE;
}
}
return FALSE;
}
BOOL existsPipe(const char* name) {
List_Foreach (n, gPipeList) {
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0) {
return TRUE;
}
}
return FALSE;
}