Merge branch 'master' of git://localhost/acess2
[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                         LOG("pipe->Buffer = %p, pipe->WritePos = %i, ofs=%i, len=%i",
357                                 pipe->Buffer, pipe->WritePos, ofs, len);
358                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
359                         memcpy(&pipe->Buffer[0], (Uint8*)Buffer + ofs, len-ofs);
360                 }
361                 else
362                 {
363                         LOG("pipe->Buffer = %p, pipe->WritePos = %i", pipe->Buffer, pipe->WritePos);
364                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
365                 }
366                 
367                 // Increment read position
368                 pipe->WritePos += len;
369                 pipe->WritePos %= pipe->BufSize;
370                 
371                 // Mark some flags
372                 if( pipe->ReadPos == pipe->WritePos ) {
373                         LOG("Buffer is full");
374                         VFS_MarkFull(Node, 1);  // Buffer full
375                 }
376                 VFS_MarkAvaliable(Node, 1);
377                 
378                 // Decrement Remaining Bytes
379                 remaining -= len;
380                 // Increment Buffer address
381                 Buffer = (Uint8*)Buffer + len;
382         }
383
384         LEAVE('i', Length);
385         return Length;
386 }
387
388 // --- HELPERS ---
389 /**
390  * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
391  * \brief Create a new pipe
392  */
393 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
394 {
395         tPipe   *ret;
396          int    namelen = strlen(Name) + 1;
397          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
398
399         ENTER("iSize sName", Size, Name);       
400
401         ret = calloc(1, allocsize);
402         if(!ret)        LEAVE_RET('n', NULL);
403         
404         // Set default flags
405         ret->Flags = PF_BLOCKING;
406         
407         // Allocate Buffer
408         ret->BufSize = Size;
409         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
410         
411         // Set name (and FIFO name)
412         ret->Name = ret->Buffer + Size;
413         strcpy(ret->Name, Name);
414         // - Start empty, max of `Size`
415         //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
416         
417         // Set Node
418         ret->Node.ReferenceCount = 1;
419         ret->Node.Size = 0;
420         ret->Node.ImplPtr = ret;
421         ret->Node.UID = Threads_GetUID();
422         ret->Node.GID = Threads_GetGID();
423         ret->Node.NumACLs = 1;
424         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
425                 ret->Node.ACLs->Group = 0;
426                 ret->Node.ACLs->ID = ret->Node.UID;
427                 ret->Node.ACLs->Inv = 0;
428                 ret->Node.ACLs->Perms = -1;
429         ret->Node.CTime
430                 = ret->Node.MTime
431                 = ret->Node.ATime = now();
432         ret->Node.Type = &gFIFO_PipeNodeType;
433
434         LEAVE('p', ret);
435         
436         return ret;
437 }

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