Kernel/VTerm - Minor cleanup to VT input (remove logging)
[tpg/acess2.git] / KernelLand / Kernel / drv / shm.c
1 /* 
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * drv/shm.c
6  * - Shared memory "device"
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <modules.h>
11 #include <fs_devfs.h>
12 #include <memfs_helpers.h> 
13 #include <semaphore.h>
14
15 #define PAGE_COUNT(v)   (((v)+(PAGE_SIZE-1))/PAGE_SIZE)
16
17 // === TYPES ===
18 #define PAGES_PER_BLOCK 1024
19 typedef struct sSHM_BufferBlock
20 {
21         struct sSHM_BufferBlock *Next;
22         tPAddr  Pages[PAGES_PER_BLOCK];
23 } tSHM_BufferBlock;
24 typedef struct
25 {
26         tMemFS_FileHdr  FileHdr;
27         tVFS_Node       Node;
28         size_t  nPages;
29         tSHM_BufferBlock        FirstBlock;
30 } tSHM_Buffer;
31
32 // === PROTOTYPES ===
33  int    SHM_Install(char **Arguments);
34  int    SHM_Uninstall(void);
35 tSHM_Buffer     *SHM_CreateBuffer(const char *Name);
36 bool    SHM_AddPages(tSHM_Buffer *Buffer, size_t num);
37 void    SHM_DeleteBuffer(tSHM_Buffer *Buffer);
38 // - Root directory
39  int    SHM_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
40 tVFS_Node       *SHM_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags);
41 tVFS_Node       *SHM_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
42  int    SHM_Unlink(tVFS_Node *Node, const char *OldName);
43 // - Buffers
44 void    SHM_Reference(tVFS_Node *Node);
45 void    SHM_Close(tVFS_Node *Node);
46 off_t   SHM_Truncate(tVFS_Node *Node, off_t NewSize);
47 size_t  SHM_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
48 size_t  SHM_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
49  int    SHM_MMap(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest);
50
51 // === GLOBALS ===
52 MODULE_DEFINE(0, 0x0100, SHM, SHM_Install, SHM_Uninstall, NULL);
53 tMemFS_DirHdr   gSHM_RootDir = {
54         .FileHdr = {.Name = "SHMRoot"}
55 };
56 tVFS_NodeType   gSHM_DirNodeType = {
57         .TypeName = "SHM Root",
58         .ReadDir = SHM_ReadDir,
59         .FindDir = SHM_FindDir,
60         .MkNod   = SHM_MkNod,
61         .Unlink  = SHM_Unlink,
62 };
63 tVFS_NodeType   gSHM_FileNodeType = {
64         .TypeName = "SHM Buffer",
65         .Read  = SHM_Read,
66         .Write = SHM_Write,
67         .Close = SHM_Close,
68         .MMap  = SHM_MMap,
69         .Truncate = SHM_Truncate,
70         .Reference = SHM_Reference,
71 };
72 tDevFS_Driver   gSHM_DriverInfo = {
73         .Name = "shm",
74         .RootNode = {
75                 .Size = 0,
76                 .NumACLs = 1,
77                 .ACLs = &gVFS_ACL_EveryoneRW,
78                 .Flags = VFS_FFLAG_DIRECTORY,
79                 .Type = &gSHM_DirNodeType
80         }
81 };
82
83 // === CODE ===
84 int SHM_Install(char **Arguments)
85 {
86         MemFS_InitDir(&gSHM_RootDir);
87         DevFS_AddDevice( &gSHM_DriverInfo );
88         return MODULE_ERR_OK;
89 }
90 int SHM_Uninstall(void)
91 {
92         return MODULE_ERR_OK;
93 }
94 tSHM_Buffer *SHM_CreateBuffer(const char *Name)
95 {
96         tSHM_Buffer *ret = calloc(1, sizeof(tSHM_Buffer) + strlen(Name) + 1);
97         MemFS_InitFile(&ret->FileHdr);
98         ret->FileHdr.Name = (const char*)(ret+1);
99         strcpy((char*)ret->FileHdr.Name, Name);
100         ret->Node.ImplPtr = ret;
101         ret->Node.Type = &gSHM_FileNodeType;
102         ret->Node.ReferenceCount = 1;
103         return ret;
104 }
105 bool SHM_AddPages(tSHM_Buffer *Buffer, size_t num)
106 {
107         tSHM_BufferBlock        *block = &Buffer->FirstBlock;
108         // Search for final block
109         size_t  idx = Buffer->nPages;
110         while( block->Next ) {
111                 block = block->Next;
112                 idx -= PAGES_PER_BLOCK;
113         }
114         ASSERTC(idx, <=, PAGES_PER_BLOCK);
115         
116         for( size_t i = 0; i < num; i ++ )
117         {
118                 if( idx == PAGES_PER_BLOCK )
119                 {
120                         block->Next = calloc(1, sizeof(tSHM_BufferBlock));
121                         if(!block->Next) {
122                                 Log_Warning("SHM", "Out of memory, allocating new buffer block");
123                                 return false;
124                         }
125                         block = block->Next;
126                         idx = 0;
127                 }
128                 ASSERT(block->Pages[idx] == 0);
129                 block->Pages[idx] = MM_AllocPhys();
130                 if( !block->Pages[idx] ) {
131                         Log_Warning("SHM", "Out of memory, allocating page");
132                         return false;
133                 }
134                 Buffer->nPages += 1;
135                 idx ++;
136         }
137         return true;
138 }
139 void SHM_DeleteBuffer(tSHM_Buffer *Buffer)
140 {
141         ASSERTCR(Buffer->Node.ReferenceCount,==,0,);
142         
143         // TODO: Destroy multi-block nodes
144         ASSERT(Buffer->FirstBlock.Next == NULL);
145         
146         free(Buffer);
147 }
148 // - Root directory
149 int SHM_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX])
150 {
151         return MemFS_ReadDir(&gSHM_RootDir, Id, Dest);
152 }
153
154 /**
155  * \brief Open a shared memory buffer
156  *
157  * \note Opening 'anon' will always succeed, and will create an anonymous mapping
158  */
159 tVFS_Node *SHM_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags)
160 {
161         if( strcmp(Filename, "anon") == 0 )
162         {
163                 tSHM_Buffer *ret = SHM_CreateBuffer("");
164                 return &ret->Node;
165         }
166         
167         tMemFS_FileHdr  *file = MemFS_FindDir(&gSHM_RootDir, Filename);
168         if( !file )
169                 return NULL;
170         
171         return &((tSHM_Buffer*)file)->Node;
172 }
173
174
175 /**
176  * \brief Create a named shared memory file
177  */
178 tVFS_Node *SHM_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
179 {
180         if( MemFS_FindDir(&gSHM_RootDir, Name) )
181                 return NULL;
182         
183         tSHM_Buffer *ret = SHM_CreateBuffer(Name);
184         if( !MemFS_Insert(&gSHM_RootDir, &ret->FileHdr) )
185         {
186                 ret->Node.ReferenceCount = 0;
187                 SHM_DeleteBuffer(ret);
188                 return NULL;
189         }
190
191         return &ret->Node;
192 }
193
194 /**
195  * \breif Remove a named shared memory buffer (will be deleted when all references drop)
196  */
197 int SHM_Unlink(tVFS_Node *Node, const char *OldName)
198 {
199         tMemFS_FileHdr  *file = MemFS_Remove(&gSHM_RootDir, OldName);
200         if( !file )
201                 return 1;
202
203         tSHM_Buffer *buf = (tSHM_Buffer*)file;
204         if( buf->Node.ReferenceCount == 0 )
205         {
206                 SHM_DeleteBuffer(buf);
207         }
208         else
209         {
210                 // dangling references, let them clean themselves up later
211         }
212         return 0;
213 }
214 // - Buffers
215 void SHM_Reference(tVFS_Node *Node)
216 {
217         Node->ReferenceCount ++;
218 }
219 void SHM_Close(tVFS_Node *Node)
220 {
221         Node->ReferenceCount --;
222         if( Node->ReferenceCount == 0 )
223         {
224                 // TODO: How to tell if a buffer should be deleted here?
225                 UNIMPLEMENTED();
226         }
227 }
228 off_t SHM_Truncate(tVFS_Node *Node, off_t NewSize)
229 {
230         ENTER("pNode XNewSize", Node, NewSize);
231         tSHM_Buffer     *buffer = Node->ImplPtr;
232         LOG("Node->Size = 0x%llx", Node->Size);
233         if( PAGE_COUNT(NewSize) != PAGE_COUNT(Node->Size) )
234         {
235                  int    page_difference = PAGE_COUNT(NewSize) - PAGE_COUNT(Node->Size);
236                 LOG("page_difference = %i", page_difference);
237                 if( page_difference < 0 )
238                 {
239                         // Truncate down
240                         // TODO: What if underlying pages are mapped?... should it matter?
241                         UNIMPLEMENTED();
242                 }
243                 else
244                 {
245                         // Truncate up
246                         SHM_AddPages(buffer, page_difference);
247                 }
248         }
249         else
250         {
251                 LOG("Page count hasn't changed");
252         }
253         Node->Size = NewSize;
254         LEAVE('X', NewSize);
255         return NewSize;
256 }
257 size_t SHM_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
258 {
259         UNIMPLEMENTED();
260         return -1;
261 }
262 size_t SHM_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
263 {
264         // TODO: Should first write determine the fixed size of the buffer?
265         UNIMPLEMENTED();
266         return -1;
267 }
268 int SHM_MMap(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest)
269 {
270         tSHM_Buffer     *buf = Node->ImplPtr;
271         if( Offset > Node->Size )       return 1;
272         if( Offset + Length > Node->Size )      return 1;
273         
274         const int pagecount = (Length + Offset % PAGE_SIZE) / PAGE_SIZE;
275         int pagenum = Offset / PAGE_SIZE;
276         
277         tSHM_BufferBlock        *block = &buf->FirstBlock;
278         while( pagenum > PAGES_PER_BLOCK ) {
279                 block = block->Next;
280                 ASSERT(block);
281                 pagenum -= PAGES_PER_BLOCK;
282         }
283         
284         tPage *dst = Dest;
285         for( int i = 0; i < pagecount; i ++ )
286         {
287                 if( pagenum == PAGES_PER_BLOCK ) {
288                         block = block->Next;
289                         ASSERT(block);
290                         pagenum = 0;
291                 }
292                 
293                 ASSERT(block->Pages[pagenum]);
294                 LOG("%p => %i:%P", dst, pagenum, block->Pages[pagenum]);
295                 MM_Map(dst, block->Pages[pagenum]);
296                 
297                 pagenum ++;
298                 dst ++;
299         }
300         return 0;
301 }
302

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