Reworked semaphores to be symetric
[tpg/acess2.git] / Kernel / drv / fifo.c
1 /* AcessOS
2  * FIFO Pipe Driver
3  */
4 #include <acess.h>
5 #include <modules.h>
6 #include <fs_devfs.h>
7 #include <semaphore.h>
8
9 // === CONSTANTS ===
10 #define DEFAULT_RING_SIZE       2048
11 #define PF_BLOCKING             1
12
13 // === TYPES ===
14 typedef struct sPipe {
15         struct sPipe    *Next;
16         char    *Name;
17         tVFS_Node       Node;
18         Uint    Flags;
19          int    ReadPos;
20          int    WritePos;
21          int    BufSize;
22         char    *Buffer;
23         tSemaphore      Semaphore;
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_Close(tVFS_Node *Node);
33  int    FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
34 Uint64  FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
35 Uint64  FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
36 tPipe   *FIFO_Int_NewPipe(int Size, char *Name);
37
38 // === GLOBALS ===
39 MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
40 tDevFS_Driver   gFIFO_DriverInfo = {
41         NULL, "fifo",
42         {
43         .Size = 1,
44         .NumACLs = 1,
45         .ACLs = &gVFS_ACL_EveryoneRW,
46         .Flags = VFS_FFLAG_DIRECTORY,
47         .ReadDir = FIFO_ReadDir,
48         .FindDir = FIFO_FindDir,
49         .MkNod = FIFO_MkNod,
50         .Relink = FIFO_Relink,
51         .IOCtl = FIFO_IOCtl
52         }
53 };
54 tVFS_Node       gFIFO_AnonNode = {
55         .NumACLs = 1,
56         .ACLs = &gVFS_ACL_EveryoneRW,
57         };
58 tPipe   *gFIFO_NamedPipes = NULL;
59
60 // === CODE ===
61 /**
62  * \fn int FIFO_Install(char **Options)
63  * \brief Installs the FIFO Driver
64  */
65 int FIFO_Install(char **Options)
66 {
67         DevFS_AddDevice( &gFIFO_DriverInfo );
68         return MODULE_ERR_OK;
69 }
70
71 /**
72  * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
73  */
74 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
75 {
76         return 0;
77 }
78
79 /**
80  * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
81  * \brief Reads from the FIFO root
82  */
83 char *FIFO_ReadDir(tVFS_Node *Node, int Id)
84 {
85         tPipe   *tmp = gFIFO_NamedPipes;
86         
87         // Entry 0 is Anon Pipes
88         if(Id == 0)     return strdup("anon");
89         
90         // Find the id'th node
91         while(--Id && tmp)      tmp = tmp->Next;
92         // If node found, return it
93         if(tmp) return strdup(tmp->Name);
94         // else error return
95         return NULL;
96 }
97
98 /**
99  * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
100  * \brief Find a file in the FIFO root
101  * \note Creates an anon pipe if anon is requested
102  */
103 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
104 {
105         tPipe   *tmp;
106         if(!Filename)   return NULL;
107         
108         // NULL String Check
109         if(Filename[0] == '\0') return NULL;
110         
111         // Anon Pipe
112         if(Filename[0] == 'a' && Filename[1] == 'n'
113         && Filename[2] == 'o' && Filename[3] == 'n'
114         && Filename[4] == '\0') {
115                 tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
116                 return &tmp->Node;
117         }
118         
119         // Check Named List
120         tmp = gFIFO_NamedPipes;
121         while(tmp)
122         {
123                 if(strcmp(tmp->Name, Filename) == 0)
124                         return &tmp->Node;
125                 tmp = tmp->Next;
126         }
127         return NULL;
128 }
129
130 /**
131  * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
132  */
133 int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
134 {
135         return 0;
136 }
137
138 /**
139  * \fn void FIFO_Close(tVFS_Node *Node)
140  * \brief Close a FIFO end
141  */
142 void FIFO_Close(tVFS_Node *Node)
143 {
144         tPipe   *pipe;
145         if(!Node->ImplPtr)      return ;
146         
147         Node->ReferenceCount --;
148         if(Node->ReferenceCount)        return ;
149         
150         pipe = Node->ImplPtr;
151         
152         if(strcmp(pipe->Name, "anon") == 0) {
153                 free(Node->ImplPtr);
154                 return ;
155         }
156         
157         return ;
158 }
159
160 /**
161  * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
162  * \brief Relink a file (Deletes named pipes)
163  */
164 int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
165 {
166         tPipe   *pipe, *tmp;
167         
168         if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
169         
170         // Can't relink anon
171         if(strcmp(OldName, "anon"))     return 0;
172         
173         // Find node
174         for(pipe = gFIFO_NamedPipes;
175                 pipe;
176                 pipe = pipe->Next)
177         {
178                 if(strcmp(pipe->Name, OldName) == 0)
179                         break;
180         }
181         if(!pipe)       return 0;
182         
183         // Relink a named pipe
184         if(NewName) {
185                 // Check new name
186                 for(tmp = gFIFO_NamedPipes;
187                         tmp;
188                         tmp = tmp->Next)
189                 {
190                         if(strcmp(tmp->Name, NewName) == 0)     return 0;
191                 }
192                 // Create new name
193                 free(pipe->Name);
194                 pipe->Name = malloc(strlen(NewName)+1);
195                 strcpy(pipe->Name, NewName);
196                 return 1;
197         }
198         
199         // Unlink the pipe
200         if(Node->ImplPtr) {
201                 free(Node->ImplPtr);
202                 return 1;
203         }
204         
205         return 0;
206 }
207
208 /**
209  * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
210  * \brief Read from a fifo pipe
211  */
212 Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
213 {
214         tPipe   *pipe = Node->ImplPtr;
215         Uint    len;
216         Uint    remaining = Length;
217         
218         if(!pipe)       return 0;
219         
220         while(remaining)
221         {
222                 // Wait for buffer to fill
223                 if(pipe->Flags & PF_BLOCKING) {
224                         len = Semaphore_Wait( &pipe->Semaphore, remaining );
225                 }
226                 else
227                 {
228                         if(pipe->ReadPos == pipe->WritePos)
229                                 return 0;
230                         // Read buffer
231                         if(pipe->WritePos - pipe->ReadPos < remaining)
232                                 len = pipe->WritePos - pipe->ReadPos;
233                         else
234                                 len = remaining;
235                 }
236                 
237                 // Check if read overflows buffer
238                 if(len > pipe->BufSize - pipe->ReadPos)
239                 {
240                         int ofs = pipe->BufSize - pipe->ReadPos;
241                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
242                         memcpy(Buffer + ofs, &pipe->Buffer, len-ofs);
243                 }
244                 else
245                 {
246                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
247                 }
248                 
249                 // Increment read position
250                 pipe->ReadPos += len;
251                 pipe->ReadPos %= pipe->BufSize;
252                 
253                 // Decrement Remaining Bytes
254                 remaining -= len;
255                 // Increment Buffer address
256                 Buffer += len;
257         }
258
259         return Length;
260
261 }
262
263 /**
264  * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
265  * \brief Write to a fifo pipe
266  */
267 Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
268 {
269         tPipe   *pipe = Node->ImplPtr;
270         Uint    len;
271         Uint    remaining = Length;
272         
273         if(!pipe)       return 0;
274         
275         while(remaining)
276         {
277                 // Wait for buffer to empty
278                 if(pipe->Flags & PF_BLOCKING) {
279                         len = Semaphore_Signal( &pipe->Semaphore, remaining );
280                 }
281                 else
282                 {
283                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
284                                 return 0;
285                         // Write buffer
286                         if(pipe->ReadPos - pipe->WritePos < remaining)
287                                 len = pipe->ReadPos - pipe->WritePos;
288                         else
289                                 len = remaining;
290                 }
291                 
292                 // Check if write overflows buffer
293                 if(len > pipe->BufSize - pipe->WritePos)
294                 {
295                         int ofs = pipe->BufSize - pipe->WritePos;
296                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
297                         memcpy(&pipe->Buffer, Buffer + ofs, len-ofs);
298                 }
299                 else
300                 {
301                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
302                 }
303                 
304                 // Increment read position
305                 pipe->WritePos += len;
306                 pipe->WritePos %= pipe->BufSize;
307                 
308                 // Decrement Remaining Bytes
309                 remaining -= len;
310                 // Increment Buffer address
311                 Buffer += len;
312         }
313
314         return Length;
315 }
316
317 // --- HELPERS ---
318 /**
319  * \fn tPipe *FIFO_Int_NewPipe(int Size, char *Name)
320  * \brief Create a new pipe
321  */
322 tPipe *FIFO_Int_NewPipe(int Size, char *Name)
323 {
324         tPipe   *ret;
325          int    namelen = strlen(Name) + 1;
326          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
327         
328         ret = malloc(allocsize);
329         if(!ret)        return NULL;
330         
331         // Clear Return
332         memset(ret, 0, allocsize);
333         ret->Flags = PF_BLOCKING;
334         
335         // Allocate Buffer
336         ret->BufSize = Size;
337         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
338         
339         // Set name (and FIFO name)
340         ret->Name = ret->Buffer + Size;
341         strcpy(ret->Name, Name);
342         // - Start empty, max of `Size`
343         Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
344         
345         // Set Node
346         ret->Node.Size = 0;
347         ret->Node.ImplPtr = ret;
348         ret->Node.UID = Threads_GetUID();
349         ret->Node.GID = Threads_GetGID();
350         ret->Node.NumACLs = 1;
351         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
352                 ret->Node.ACLs->Group = 0;
353                 ret->Node.ACLs->ID = ret->Node.UID;
354                 ret->Node.ACLs->Inv = 0;
355                 ret->Node.ACLs->Perms = -1;
356         ret->Node.CTime
357                 = ret->Node.MTime
358                 = ret->Node.ATime = now();
359         ret->Node.Read = FIFO_Read;
360         ret->Node.Write = FIFO_Write;
361         ret->Node.Close = FIFO_Close;
362         
363         return ret;
364 }

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