Kernel - Update VFS API to use off_t/size_t instead of Uint64
[tpg/acess2.git] / KernelLand / 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 size_t  FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
36 size_t  FIFO_Write(tVFS_Node *Node, off_t Offset, size_t 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  * \brief Read from a fifo pipe
230  */
231 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
232 {
233         tPipe   *pipe = Node->ImplPtr;
234         Uint    len;
235         Uint    remaining = Length;
236
237         if(!pipe)       return 0;
238         
239         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
240         
241         while(remaining)
242         {
243                 // Wait for buffer to fill
244                 if(pipe->Flags & PF_BLOCKING)
245                 {
246                         if( pipe->ReadPos == pipe->WritePos )
247                                 VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
248                         
249                 }
250                 else
251                 {
252                         if(pipe->ReadPos == pipe->WritePos)
253                         {
254                                 VFS_MarkAvaliable(Node, 0);
255                                 LEAVE('i', 0);
256                                 return 0;
257                         }
258                 }
259         
260                 len = remaining;
261                 if( pipe->ReadPos < pipe->WritePos )
262                 {
263                          int    avail_bytes = pipe->WritePos - pipe->ReadPos;
264                         if( avail_bytes < remaining )   len = avail_bytes;
265                 }
266                 else
267                 {
268                          int    avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
269                         if( avail_bytes < remaining )   len = avail_bytes;
270                 }
271
272                 LOG("len = %i, remaining = %i", len, remaining);                
273
274                 // Check if read overflows buffer
275                 if(len > pipe->BufSize - pipe->ReadPos)
276                 {
277                         int ofs = pipe->BufSize - pipe->ReadPos;
278                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
279                         memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
280                 }
281                 else
282                 {
283                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
284                 }
285                 
286                 // Increment read position
287                 pipe->ReadPos += len;
288                 pipe->ReadPos %= pipe->BufSize;
289                 
290                 // Mark some flags
291                 if( pipe->ReadPos == pipe->WritePos ) {
292                         VFS_MarkAvaliable(Node, 0);
293                 }
294                 VFS_MarkFull(Node, 0);  // Buffer can't still be full
295                 
296                 // Decrement Remaining Bytes
297                 remaining -= len;
298                 // Increment Buffer address
299                 Buffer = (Uint8*)Buffer + len;
300                 
301                 // TODO: Option to read differently
302                 LEAVE('i', len);
303                 return len;
304         }
305
306         LEAVE('i', Length);
307         return Length;
308
309 }
310
311 /**
312  * \brief Write to a fifo pipe
313  */
314 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
315 {
316         tPipe   *pipe = Node->ImplPtr;
317         Uint    len;
318         Uint    remaining = Length;
319         
320         if(!pipe)       return 0;
321
322         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
323         
324         while(remaining)
325         {
326                 // Wait for buffer to empty
327                 if(pipe->Flags & PF_BLOCKING) {
328                         if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
329                                 VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
330
331                         len = remaining;
332                         if( pipe->ReadPos > pipe->WritePos )
333                         {
334                                  int    rem_space = pipe->ReadPos - pipe->WritePos;
335                                 if(rem_space < remaining)       len = rem_space;
336                         }
337                         else
338                         {
339                                  int    rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
340                                 if(rem_space < remaining)       len = rem_space;
341                         }
342                 }
343                 else
344                 {
345                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
346                         {
347                                 LEAVE('i', 0);
348                                 return 0;
349                         }
350                         // Write buffer
351                         if(pipe->ReadPos - pipe->WritePos < remaining)
352                                 len = pipe->ReadPos - pipe->WritePos;
353                         else
354                                 len = remaining;
355                 }
356                 
357                 // Check if write overflows buffer
358                 if(len > pipe->BufSize - pipe->WritePos)
359                 {
360                         int ofs = pipe->BufSize - pipe->WritePos;
361                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
362                         memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
363                 }
364                 else
365                 {
366                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
367                 }
368                 
369                 // Increment read position
370                 pipe->WritePos += len;
371                 pipe->WritePos %= pipe->BufSize;
372                 
373                 // Mark some flags
374                 if( pipe->ReadPos == pipe->WritePos ) {
375                         VFS_MarkFull(Node, 1);  // Buffer full
376                 }
377                 VFS_MarkAvaliable(Node, 1);
378                 
379                 // Decrement Remaining Bytes
380                 remaining -= len;
381                 // Increment Buffer address
382                 Buffer = (Uint8*)Buffer + len;
383         }
384
385         LEAVE('i', Length);
386         return Length;
387 }
388
389 // --- HELPERS ---
390 /**
391  * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
392  * \brief Create a new pipe
393  */
394 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
395 {
396         tPipe   *ret;
397          int    namelen = strlen(Name) + 1;
398          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
399         
400         ret = calloc(1, allocsize);
401         if(!ret)        return NULL;
402         
403         // Clear Return
404         ret->Flags = PF_BLOCKING;
405         
406         // Allocate Buffer
407         ret->BufSize = Size;
408         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
409         
410         // Set name (and FIFO name)
411         ret->Name = ret->Buffer + Size;
412         strcpy(ret->Name, Name);
413         // - Start empty, max of `Size`
414         //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
415         
416         // Set Node
417         ret->Node.ReferenceCount = 1;
418         ret->Node.Size = 0;
419         ret->Node.ImplPtr = ret;
420         ret->Node.UID = Threads_GetUID();
421         ret->Node.GID = Threads_GetGID();
422         ret->Node.NumACLs = 1;
423         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
424                 ret->Node.ACLs->Group = 0;
425                 ret->Node.ACLs->ID = ret->Node.UID;
426                 ret->Node.ACLs->Inv = 0;
427                 ret->Node.ACLs->Perms = -1;
428         ret->Node.CTime
429                 = ret->Node.MTime
430                 = ret->Node.ATime = now();
431         ret->Node.Type = &gFIFO_PipeNodeType;
432         
433         return ret;
434 }

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