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

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