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

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