Merge branch 'master' of git://localhost/acess2
[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_Unlink(tVFS_Node *Node, const char *OldName);
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         .Unlink = FIFO_Unlink,
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  * \brief Delete a pipe
182  */
183 int FIFO_Unlink(tVFS_Node *Node, const char *OldName)
184 {
185         tPipe   *pipe;
186         
187         if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
188         
189         // Can't relink anon
190         if(strcmp(OldName, "anon"))     return 0;
191         
192         // Find node
193         for(pipe = gFIFO_NamedPipes;
194                 pipe;
195                 pipe = pipe->Next)
196         {
197                 if(strcmp(pipe->Name, OldName) == 0)
198                         break;
199         }
200         if(!pipe)       return 0;
201         
202         // Unlink the pipe
203         if(Node->ImplPtr) {
204                 free(Node->ImplPtr);
205                 return 1;
206         }
207         
208         return 0;
209 }
210
211 /**
212  * \brief Read from a fifo pipe
213  */
214 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
215 {
216         tPipe   *pipe = Node->ImplPtr;
217         Uint    len;
218         Uint    remaining = Length;
219
220         if(!pipe)       return 0;
221         
222         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
223         
224         while(remaining)
225         {
226                 // Wait for buffer to fill
227                 if(pipe->Flags & PF_BLOCKING)
228                 {
229                         if( pipe->ReadPos == pipe->WritePos )
230                                 VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
231                         
232                 }
233                 else
234                 {
235                         if(pipe->ReadPos == pipe->WritePos)
236                         {
237                                 VFS_MarkAvaliable(Node, 0);
238                                 LEAVE('i', 0);
239                                 return 0;
240                         }
241                 }
242         
243                 len = remaining;
244                 if( pipe->ReadPos < pipe->WritePos )
245                 {
246                          int    avail_bytes = pipe->WritePos - pipe->ReadPos;
247                         if( avail_bytes < remaining )   len = avail_bytes;
248                 }
249                 else
250                 {
251                          int    avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
252                         if( avail_bytes < remaining )   len = avail_bytes;
253                 }
254
255                 LOG("len = %i, remaining = %i", len, remaining);                
256
257                 // Check if read overflows buffer
258                 if(len > pipe->BufSize - pipe->ReadPos)
259                 {
260                         int ofs = pipe->BufSize - pipe->ReadPos;
261                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
262                         memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
263                 }
264                 else
265                 {
266                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
267                 }
268                 
269                 // Increment read position
270                 pipe->ReadPos += len;
271                 pipe->ReadPos %= pipe->BufSize;
272                 
273                 // Mark some flags
274                 if( pipe->ReadPos == pipe->WritePos ) {
275                         VFS_MarkAvaliable(Node, 0);
276                 }
277                 VFS_MarkFull(Node, 0);  // Buffer can't still be full
278                 
279                 // Decrement Remaining Bytes
280                 remaining -= len;
281                 // Increment Buffer address
282                 Buffer = (Uint8*)Buffer + len;
283                 
284                 // TODO: Option to read differently
285                 LEAVE('i', len);
286                 return len;
287         }
288
289         LEAVE('i', Length);
290         return Length;
291
292 }
293
294 /**
295  * \brief Write to a fifo pipe
296  */
297 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
298 {
299         tPipe   *pipe = Node->ImplPtr;
300         Uint    len;
301         Uint    remaining = Length;
302         
303         if(!pipe)       return 0;
304
305         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
306         
307         while(remaining)
308         {
309                 // Wait for buffer to empty
310                 if(pipe->Flags & PF_BLOCKING) {
311                         if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
312                                 VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
313
314                         len = remaining;
315                         if( pipe->ReadPos > pipe->WritePos )
316                         {
317                                  int    rem_space = pipe->ReadPos - pipe->WritePos;
318                                 if(rem_space < remaining)       len = rem_space;
319                         }
320                         else
321                         {
322                                  int    rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
323                                 if(rem_space < remaining)       len = rem_space;
324                         }
325                 }
326                 else
327                 {
328                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
329                         {
330                                 LEAVE('i', 0);
331                                 return 0;
332                         }
333                         // Write buffer
334                         if(pipe->ReadPos - pipe->WritePos < remaining)
335                                 len = pipe->ReadPos - pipe->WritePos;
336                         else
337                                 len = remaining;
338                 }
339                 
340                 // Check if write overflows buffer
341                 if(len > pipe->BufSize - pipe->WritePos)
342                 {
343                         int ofs = pipe->BufSize - pipe->WritePos;
344                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
345                         memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
346                 }
347                 else
348                 {
349                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
350                 }
351                 
352                 // Increment read position
353                 pipe->WritePos += len;
354                 pipe->WritePos %= pipe->BufSize;
355                 
356                 // Mark some flags
357                 if( pipe->ReadPos == pipe->WritePos ) {
358                         VFS_MarkFull(Node, 1);  // Buffer full
359                 }
360                 VFS_MarkAvaliable(Node, 1);
361                 
362                 // Decrement Remaining Bytes
363                 remaining -= len;
364                 // Increment Buffer address
365                 Buffer = (Uint8*)Buffer + len;
366         }
367
368         LEAVE('i', Length);
369         return Length;
370 }
371
372 // --- HELPERS ---
373 /**
374  * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
375  * \brief Create a new pipe
376  */
377 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
378 {
379         tPipe   *ret;
380          int    namelen = strlen(Name) + 1;
381          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
382         
383         ret = calloc(1, allocsize);
384         if(!ret)        return NULL;
385         
386         // Clear Return
387         ret->Flags = PF_BLOCKING;
388         
389         // Allocate Buffer
390         ret->BufSize = Size;
391         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
392         
393         // Set name (and FIFO name)
394         ret->Name = ret->Buffer + Size;
395         strcpy(ret->Name, Name);
396         // - Start empty, max of `Size`
397         //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
398         
399         // Set Node
400         ret->Node.ReferenceCount = 1;
401         ret->Node.Size = 0;
402         ret->Node.ImplPtr = ret;
403         ret->Node.UID = Threads_GetUID();
404         ret->Node.GID = Threads_GetGID();
405         ret->Node.NumACLs = 1;
406         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
407                 ret->Node.ACLs->Group = 0;
408                 ret->Node.ACLs->ID = ret->Node.UID;
409                 ret->Node.ACLs->Inv = 0;
410                 ret->Node.ACLs->Perms = -1;
411         ret->Node.CTime
412                 = ret->Node.MTime
413                 = ret->Node.ATime = now();
414         ret->Node.Type = &gFIFO_PipeNodeType;
415         
416         return ret;
417 }

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