Usermode/libunicode - Hack, see diff :)
[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                         VFS_MarkAvaliable(Node, 0);
284                 }
285                 VFS_MarkFull(Node, 0);  // Buffer can't still be full
286                 
287                 // Decrement Remaining Bytes
288                 remaining -= len;
289                 // Increment Buffer address
290                 Buffer = (Uint8*)Buffer + len;
291                 
292                 // TODO: Option to read differently
293                 LEAVE('i', len);
294                 return len;
295         }
296
297         LEAVE('i', Length);
298         return Length;
299
300 }
301
302 /**
303  * \brief Write to a fifo pipe
304  */
305 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
306 {
307         tPipe   *pipe = Node->ImplPtr;
308         Uint    len;
309         Uint    remaining = Length;
310         
311         if(!pipe)       return 0;
312
313         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
314         
315         while(remaining)
316         {
317                 // Wait for buffer to empty
318                 if(pipe->Flags & PF_BLOCKING) {
319                         if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
320                                 VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
321
322                         len = remaining;
323                         if( pipe->ReadPos > pipe->WritePos )
324                         {
325                                  int    rem_space = pipe->ReadPos - pipe->WritePos;
326                                 if(rem_space < remaining)       len = rem_space;
327                         }
328                         else
329                         {
330                                  int    rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
331                                 if(rem_space < remaining)       len = rem_space;
332                         }
333                 }
334                 else
335                 {
336                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
337                         {
338                                 LEAVE('i', 0);
339                                 return 0;
340                         }
341                         // Write buffer
342                         if(pipe->ReadPos - pipe->WritePos < remaining)
343                                 len = pipe->ReadPos - pipe->WritePos;
344                         else
345                                 len = remaining;
346                 }
347                 
348                 // Check if write overflows buffer
349                 if(len > pipe->BufSize - pipe->WritePos)
350                 {
351                         int ofs = pipe->BufSize - pipe->WritePos;
352                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
353                         memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
354                 }
355                 else
356                 {
357                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
358                 }
359                 
360                 // Increment read position
361                 pipe->WritePos += len;
362                 pipe->WritePos %= pipe->BufSize;
363                 
364                 // Mark some flags
365                 if( pipe->ReadPos == pipe->WritePos ) {
366                         VFS_MarkFull(Node, 1);  // Buffer full
367                 }
368                 VFS_MarkAvaliable(Node, 1);
369                 
370                 // Decrement Remaining Bytes
371                 remaining -= len;
372                 // Increment Buffer address
373                 Buffer = (Uint8*)Buffer + len;
374         }
375
376         LEAVE('i', Length);
377         return Length;
378 }
379
380 // --- HELPERS ---
381 /**
382  * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
383  * \brief Create a new pipe
384  */
385 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
386 {
387         tPipe   *ret;
388          int    namelen = strlen(Name) + 1;
389          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
390
391         ENTER("iSize sName", Size, Name);       
392
393         ret = calloc(1, allocsize);
394         if(!ret)        LEAVE_RET('n', NULL);
395         
396         // Clear Return
397         ret->Flags = PF_BLOCKING;
398         
399         // Allocate Buffer
400         ret->BufSize = Size;
401         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
402         
403         // Set name (and FIFO name)
404         ret->Name = ret->Buffer + Size;
405         strcpy(ret->Name, Name);
406         // - Start empty, max of `Size`
407         //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
408         
409         // Set Node
410         ret->Node.ReferenceCount = 1;
411         ret->Node.Size = 0;
412         ret->Node.ImplPtr = ret;
413         ret->Node.UID = Threads_GetUID();
414         ret->Node.GID = Threads_GetGID();
415         ret->Node.NumACLs = 1;
416         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
417                 ret->Node.ACLs->Group = 0;
418                 ret->Node.ACLs->ID = ret->Node.UID;
419                 ret->Node.ACLs->Inv = 0;
420                 ret->Node.ACLs->Perms = -1;
421         ret->Node.CTime
422                 = ret->Node.MTime
423                 = ret->Node.ATime = now();
424         ret->Node.Type = &gFIFO_PipeNodeType;
425
426         LEAVE('p', ret);
427         
428         return ret;
429 }

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