Bugfixing
[tpg/acess2.git] / Kernel / drv / fifo.c
1 /* AcessOS
2  * FIFO Pipe Driver
3  */
4 #include <acess.h>
5 #include <modules.h>
6 #include <fs_devfs.h>
7 #include <semaphore.h>
8
9 // === CONSTANTS ===
10 #define DEFAULT_RING_SIZE       2048
11 #define PF_BLOCKING             1
12
13 // === TYPES ===
14 typedef struct sPipe {
15         struct sPipe    *Next;
16         char    *Name;
17         tVFS_Node       Node;
18         Uint    Flags;
19          int    ReadPos;
20          int    WritePos;
21          int    BufSize;
22         char    *Buffer;
23 } tPipe;
24
25 // === PROTOTYPES ===
26  int    FIFO_Install(char **Arguments);
27  int    FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
28 char    *FIFO_ReadDir(tVFS_Node *Node, int Id);
29 tVFS_Node       *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
30  int    FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
31 void    FIFO_Close(tVFS_Node *Node);
32  int    FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
33 Uint64  FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
34 Uint64  FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
35 tPipe   *FIFO_Int_NewPipe(int Size, const char *Name);
36
37 // === GLOBALS ===
38 MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
39 tVFS_NodeType   gFIFO_DirNodeType = {
40         .TypeName = "FIFO Dir Node",
41         .ReadDir = FIFO_ReadDir,
42         .FindDir = FIFO_FindDir,
43         .MkNod = FIFO_MkNod,
44         .Relink = FIFO_Relink,
45         .IOCtl = FIFO_IOCtl
46 };
47 tVFS_NodeType   gFIFO_PipeNodeType = {
48         .TypeName = "FIFO Pipe Node",
49         .Read = FIFO_Read,
50         .Write = FIFO_Write,
51         .Close = FIFO_Close
52 };
53 tDevFS_Driver   gFIFO_DriverInfo = {
54         NULL, "fifo",
55         {
56         .Size = 1,
57         .NumACLs = 1,
58         .ACLs = &gVFS_ACL_EveryoneRW,
59         .Flags = VFS_FFLAG_DIRECTORY,
60         .Type = &gFIFO_DirNodeType
61         }
62 };
63 tVFS_Node       gFIFO_AnonNode = {
64         .NumACLs = 1,
65         .ACLs = &gVFS_ACL_EveryoneRW,
66         };
67 tPipe   *gFIFO_NamedPipes = NULL;
68
69 // === CODE ===
70 /**
71  * \fn int FIFO_Install(char **Options)
72  * \brief Installs the FIFO Driver
73  */
74 int FIFO_Install(char **Options)
75 {
76         DevFS_AddDevice( &gFIFO_DriverInfo );
77         return MODULE_ERR_OK;
78 }
79
80 /**
81  * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
82  */
83 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
84 {
85         return 0;
86 }
87
88 /**
89  * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
90  * \brief Reads from the FIFO root
91  */
92 char *FIFO_ReadDir(tVFS_Node *Node, int Id)
93 {
94         tPipe   *tmp = gFIFO_NamedPipes;
95         
96         // Entry 0 is Anon Pipes
97         if(Id == 0)     return strdup("anon");
98         
99         // Find the id'th node
100         while(--Id && tmp)      tmp = tmp->Next;
101         // If node found, return it
102         if(tmp) return strdup(tmp->Name);
103         // else error return
104         return NULL;
105 }
106
107 /**
108  * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
109  * \brief Find a file in the FIFO root
110  * \note Creates an anon pipe if anon is requested
111  */
112 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
113 {
114         tPipe   *tmp;
115         if(!Filename)   return NULL;
116         
117         // NULL String Check
118         if(Filename[0] == '\0') return NULL;
119         
120         // Anon Pipe
121         if(Filename[0] == 'a' && Filename[1] == 'n'
122         && Filename[2] == 'o' && Filename[3] == 'n'
123         && Filename[4] == '\0') {
124                 tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
125                 return &tmp->Node;
126         }
127         
128         // Check Named List
129         tmp = gFIFO_NamedPipes;
130         while(tmp)
131         {
132                 if(strcmp(tmp->Name, Filename) == 0)
133                         return &tmp->Node;
134                 tmp = tmp->Next;
135         }
136         return NULL;
137 }
138
139 /**
140  * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
141  */
142 int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
143 {
144         return 0;
145 }
146
147 /**
148  * \fn void FIFO_Close(tVFS_Node *Node)
149  * \brief Close a FIFO end
150  */
151 void FIFO_Close(tVFS_Node *Node)
152 {
153         tPipe   *pipe;
154         if(!Node->ImplPtr)      return ;
155         
156         Node->ReferenceCount --;
157         if(Node->ReferenceCount)        return ;
158         
159         pipe = Node->ImplPtr;
160         
161         if(strcmp(pipe->Name, "anon") == 0) {
162                 free(Node->ImplPtr);
163                 return ;
164         }
165         
166         return ;
167 }
168
169 /**
170  * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
171  * \brief Relink a file (Deletes named pipes)
172  */
173 int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
174 {
175         tPipe   *pipe, *tmp;
176         
177         if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
178         
179         // Can't relink anon
180         if(strcmp(OldName, "anon"))     return 0;
181         
182         // Find node
183         for(pipe = gFIFO_NamedPipes;
184                 pipe;
185                 pipe = pipe->Next)
186         {
187                 if(strcmp(pipe->Name, OldName) == 0)
188                         break;
189         }
190         if(!pipe)       return 0;
191         
192         // Relink a named pipe
193         if(NewName) {
194                 // Check new name
195                 for(tmp = gFIFO_NamedPipes;
196                         tmp;
197                         tmp = tmp->Next)
198                 {
199                         if(strcmp(tmp->Name, NewName) == 0)     return 0;
200                 }
201                 // Create new name
202                 free(pipe->Name);
203                 pipe->Name = malloc(strlen(NewName)+1);
204                 strcpy(pipe->Name, NewName);
205                 return 1;
206         }
207         
208         // Unlink the pipe
209         if(Node->ImplPtr) {
210                 free(Node->ImplPtr);
211                 return 1;
212         }
213         
214         return 0;
215 }
216
217 /**
218  * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
219  * \brief Read from a fifo pipe
220  */
221 Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
222 {
223         tPipe   *pipe = Node->ImplPtr;
224         Uint    len;
225         Uint    remaining = Length;
226         
227         if(!pipe)       return 0;
228         
229         while(remaining)
230         {
231                 // Wait for buffer to fill
232                 if(pipe->Flags & PF_BLOCKING)
233                 {
234                         #if 0
235                         len = Semaphore_Wait( &pipe->Semaphore, remaining );
236                         #else
237                         VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
238                         // Read buffer
239                         // TODO: Rethink this, it might not work on buffer overflow
240                         if(pipe->WritePos - pipe->ReadPos < remaining)
241                                 len = pipe->WritePos - pipe->ReadPos;
242                         else
243                                 len = remaining;
244                         #endif
245                 }
246                 else
247                 {
248                         if(pipe->ReadPos == pipe->WritePos)
249                                 return 0;
250                         // Read buffer
251                         if(pipe->WritePos - pipe->ReadPos < remaining)
252                                 len = pipe->WritePos - pipe->ReadPos;
253                         else
254                                 len = remaining;
255                 }
256                 
257                 // Check if read overflows buffer
258                 if(len > pipe->BufSize - pipe->ReadPos)
259                 {
260                         int ofs = pipe->BufSize - pipe->ReadPos;
261                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
262                         memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
263                 }
264                 else
265                 {
266                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
267                 }
268                 
269                 // Increment read position
270                 pipe->ReadPos += len;
271                 pipe->ReadPos %= pipe->BufSize;
272                 
273                 // Mark some flags
274                 if( pipe->ReadPos == pipe->WritePos ) {
275                         VFS_MarkAvaliable(Node, 0);
276                 }
277                 VFS_MarkFull(Node, 0);  // Buffer can't still be full
278                 
279                 // Decrement Remaining Bytes
280                 remaining -= len;
281                 // Increment Buffer address
282                 Buffer = (Uint8*)Buffer + len;
283         }
284
285         return Length;
286
287 }
288
289 /**
290  * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
291  * \brief Write to a fifo pipe
292  */
293 Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
294 {
295         tPipe   *pipe = Node->ImplPtr;
296         Uint    len;
297         Uint    remaining = Length;
298         
299         if(!pipe)       return 0;
300         
301         while(remaining)
302         {
303                 // Wait for buffer to empty
304                 if(pipe->Flags & PF_BLOCKING) {
305                         #if 0
306                         len = Semaphore_Signal( &pipe->Semaphore, remaining );
307                         #else
308                         VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
309                         if(pipe->ReadPos - pipe->WritePos < remaining)
310                                 len = pipe->ReadPos - pipe->WritePos;
311                         else
312                                 len = remaining;
313                         #endif
314                 }
315                 else
316                 {
317                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
318                                 return 0;
319                         // Write buffer
320                         if(pipe->ReadPos - pipe->WritePos < remaining)
321                                 len = pipe->ReadPos - pipe->WritePos;
322                         else
323                                 len = remaining;
324                 }
325                 
326                 // Check if write overflows buffer
327                 if(len > pipe->BufSize - pipe->WritePos)
328                 {
329                         int ofs = pipe->BufSize - pipe->WritePos;
330                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
331                         memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
332                 }
333                 else
334                 {
335                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
336                 }
337                 
338                 // Increment read position
339                 pipe->WritePos += len;
340                 pipe->WritePos %= pipe->BufSize;
341                 
342                 // Mark some flags
343                 if( pipe->ReadPos == pipe->WritePos ) {
344                         VFS_MarkFull(Node, 1);  // Buffer full
345                 }
346                 VFS_MarkAvaliable(Node, 1);
347                 
348                 // Decrement Remaining Bytes
349                 remaining -= len;
350                 // Increment Buffer address
351                 Buffer = (Uint8*)Buffer + len;
352         }
353
354         return Length;
355 }
356
357 // --- HELPERS ---
358 /**
359  * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
360  * \brief Create a new pipe
361  */
362 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
363 {
364         tPipe   *ret;
365          int    namelen = strlen(Name) + 1;
366          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
367         
368         ret = malloc(allocsize);
369         if(!ret)        return NULL;
370         
371         // Clear Return
372         memset(ret, 0, allocsize);
373         ret->Flags = PF_BLOCKING;
374         
375         // Allocate Buffer
376         ret->BufSize = Size;
377         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
378         
379         // Set name (and FIFO name)
380         ret->Name = ret->Buffer + Size;
381         strcpy(ret->Name, Name);
382         // - Start empty, max of `Size`
383         //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
384         
385         // Set Node
386         ret->Node.Size = 0;
387         ret->Node.ImplPtr = ret;
388         ret->Node.UID = Threads_GetUID();
389         ret->Node.GID = Threads_GetGID();
390         ret->Node.NumACLs = 1;
391         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
392                 ret->Node.ACLs->Group = 0;
393                 ret->Node.ACLs->ID = ret->Node.UID;
394                 ret->Node.ACLs->Inv = 0;
395                 ret->Node.ACLs->Perms = -1;
396         ret->Node.CTime
397                 = ret->Node.MTime
398                 = ret->Node.ATime = now();
399         ret->Node.Type = &gFIFO_PipeNodeType;
400         
401         return ret;
402 }

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