Updated PCI IDs to latest snapshot.
[tangerine.git] / rom / dos / lddemon.c
blobfbff44ba94bca429fac2d2e7af84de02f8b60439
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Loader for shared libraries and devices.
6 */
8 #include <exec/execbase.h>
9 #include <exec/resident.h>
10 #include <exec/memory.h>
11 #include <exec/errors.h>
12 #include <exec/libraries.h>
13 #include <exec/devices.h>
14 #include <exec/ports.h>
15 #include <exec/lists.h>
16 #include <exec/alerts.h>
17 #include <exec/tasks.h>
18 #include <dos/dos.h>
19 #include <dos/dosextens.h>
20 #include <dos/dostags.h>
21 #include <aros/asmcall.h>
22 #define DEBUG 0
23 #include <aros/debug.h>
25 #include <proto/exec.h>
26 #include <proto/dos.h>
27 #include "dos_intern.h"
28 #include LC_LIBDEFS_FILE
30 #include <string.h>
32 #undef SysBase
34 #define CHECK_DEPENDENCY 1
36 /* Please leave them here! They are needed on Linux-M68K */
37 AROS_LD2(struct Library *, OpenLibrary,
38 AROS_LDA(STRPTR, libname, A1),
39 AROS_LDA(ULONG, version, D0),
40 struct ExecBase *, SysBase, 0, Dos);
41 AROS_LD4(BYTE, OpenDevice,
42 AROS_LDA(STRPTR, devname, A0),
43 AROS_LDA(ULONG, unitNumber, D0),
44 AROS_LDA(struct IORequest *, iORequest, A1),
45 AROS_LDA(ULONG, flags, D1),
46 struct ExecBase *, SysBase, 0, Dos);
47 AROS_LD1(void, CloseLibrary,
48 AROS_LDA(struct Library *, library, A1),
49 struct ExecBase *, SysBase, 0, Dos);
50 AROS_LD1(void, CloseDevice,
51 AROS_LDA(struct IORequest *, iORequest, A1),
52 struct ExecBase *, SysBase, 0, Dos);
53 AROS_LD1(void, RemLibrary,
54 AROS_LDA(struct Library *, library, A1),
55 struct ExecBase *, SysBase, 0, Dos);
57 struct LDDMsg
59 struct Message ldd_Msg; /* Message link */
60 struct MsgPort ldd_ReplyPort; /* Callers ReplyPort */
62 STRPTR ldd_Name; /* Name of thing to load */
63 ULONG ldd_Version; /* Version of thing to load */
65 STRPTR ldd_BaseDir; /* Base directory to load from */
66 struct Library * ldd_Return; /* The result */
69 #ifdef LIBEND
70 #undef LIBEND
71 #endif
72 #define LIBEND LDDemon_end
74 #include <libcore/compiler.h>
76 static const char name[];
77 static const char version[];
78 extern const int LIBEND TEXT_SECTION;
79 static ULONG AROS_SLIB_ENTRY(Init, LDDemon)();
81 const struct Resident LDDemon_resident =
83 RTC_MATCHWORD,
84 (struct Resident *)&LDDemon_resident,
85 &LIBEND,
86 RTF_AFTERDOS,
87 VERSION_NUMBER,
88 NT_PROCESS,
89 -123,
90 (STRPTR)name,
91 (STRPTR)&version[6],
92 AROS_SLIB_ENTRY(Init,LDDemon)
95 static const char name[] = "LDDemon";
96 static const char version[] = "$VER: LDDemon 41.3 (11.3.2007)\r\n";
97 static const char ldDemonName[] = "Lib & Dev Loader Daemon";
100 BPTR LDLoad( caller, name, basedir, DOSBase )
101 Try and load a segment from disk for the object <name>, relative
102 to directory <basedir>. Will also try <caller>'s current and home
103 directories.
105 static BPTR
106 LDLoad(
107 struct Process *caller,
108 STRPTR name,
109 STRPTR basedir,
110 struct DosLibrary *DOSBase
113 struct ExecBase *SysBase = DOSBase->dl_SysBase;
114 struct Process *me = (struct Process *)FindTask(NULL);
115 BPTR seglist = NULL;
116 STRPTR path;
117 ULONG pathLen;
118 int delimPos;
121 If the caller was a process, we have more scope for loading
122 libraries. We can load them from the callers current directory,
123 or from the PROGDIR: assign. These could both be the same
124 though.
126 D(bug(
127 "[LDLoad] caller=(%p) %s, name=%s, basedir=%s\n",
128 caller, caller->pr_Task.tc_Node.ln_Name, name, basedir
131 if (strncmp(name, "PROGDIR:", 8) == 0)
133 /* Special case for explicit PROGDIR-based path */
134 if (__is_process(caller))
136 if (caller->pr_HomeDir != NULL)
138 BPTR oldHomeDir = me->pr_HomeDir;
139 D(bug("[LDLoad] Trying homedir\n"));
140 /* Temporarily override pr_HomeDir to let GetDeviceProc handle
141 PROGDIR: case correctly while opening library file */
142 me->pr_HomeDir = caller->pr_HomeDir;
143 seglist = LoadSeg(name);
144 me->pr_HomeDir = oldHomeDir;
148 else if (!strstr(name, ":")) {
149 delimPos = strlen(basedir);
150 pathLen = delimPos + strlen(name) + 2;
151 path = AllocMem(pathLen, MEMF_ANY);
152 if (path) {
153 strcpy(path, basedir);
154 path[delimPos] = '/';
155 strcpy(&path[delimPos + 1], name);
157 if (__is_process(caller))
159 /* Try the current directory of the caller */
161 D(bug("[LDLoad] Process\n"));
162 me->pr_CurrentDir = caller->pr_CurrentDir;
163 D(bug("[LDLoad] Trying currentdir\n"));
164 seglist = LoadSeg(name);
165 if ((!seglist) && path)
166 seglist = LoadSeg(path);
168 /* The the program directory of the caller */
169 if((!seglist) && (caller->pr_HomeDir != NULL))
171 D(bug("[LDLoad] Trying homedir\n"));
172 me->pr_CurrentDir = caller->pr_HomeDir;
173 seglist = LoadSeg(name);
174 if ((!seglist) && path)
175 seglist = LoadSeg(path);
179 if (path) {
180 if (!seglist) {
181 /* Nup, lets try the default directory as supplied. */
182 D(bug("[LDLoad] Trying defaultir\n"));
183 path[delimPos] = ':';
184 seglist = LoadSeg(path);
186 FreeMem(path, pathLen);
188 } else
189 seglist =LoadSeg(name);
191 return seglist;
195 Library *LDInit(seglist, DOSBase)
196 Initialise the library.
198 static struct Library *
199 LDInit(BPTR seglist, struct DosLibrary *DOSBase)
201 struct ExecBase *SysBase = DOSBase->dl_SysBase;
202 BPTR seg = seglist;
204 while(seg)
206 STRPTR addr= (STRPTR)((IPTR)BADDR(seg)-sizeof(ULONG));
207 ULONG size = *(ULONG *)addr;
209 for(
210 addr += sizeof(BPTR) + sizeof(ULONG),
211 size -= sizeof(BPTR) + sizeof(ULONG);
212 size >= sizeof(struct Resident) ;
213 size -= 2, addr += 2
214 // size -= AROS_PTRALIGN, addr += AROS_PTRALIGN
217 struct Resident *res = (struct Resident *)addr;
218 if( res->rt_MatchWord == RTC_MATCHWORD
219 && res->rt_MatchTag == res )
221 struct Library *lib;
223 D(bug("[LDInit] Calling InitResident(%p) on %s\n", res, res->rt_Name));
224 Forbid();
225 lib = InitResident(res, seglist);
226 Permit();
227 D(bug("[LDInit] Done calling InitResident(%p) on %s\n", res, res->rt_Name));
228 if( lib == NULL )
229 UnLoadSeg(seglist);
230 return lib;
233 seg = *(BPTR *)BADDR(seg);
235 D(bug("[LDInit] Couldn't find Resident for %p\n", seglist));
236 UnLoadSeg(seglist);
237 return NULL;
240 struct Library *(*__OpenLibrary)();
241 BYTE (*__OpenDevice)();
243 #define ExecOpenLibrary(libname, version) \
244 AROS_CALL2(struct Library *, __OpenLibrary, \
245 AROS_LCA(STRPTR, libname, A1), \
246 AROS_LCA(ULONG, version, D0), \
247 struct ExecBase *, SysBase)
249 #define ExecOpenDevice(devname, unitNumber, iORequest, flags) \
250 AROS_CALL4(BYTE, __OpenDevice, \
251 AROS_LCA(STRPTR, devname, A0), \
252 AROS_LCA(ULONG, unitNumber, D0), \
253 AROS_LCA(struct IORequest *, iORequest, A1), \
254 AROS_LCA(ULONG, flags, D1), \
255 struct ExecBase *, SysBase)
258 struct Library *AROS_SLIB_ENTRY(OpenLibrary, Exec)();
259 BYTE AROS_SLIB_ENTRY(OpenDevice, Exec)();
261 #define ExecOpenLibrary(libname, version) \
262 AROS_CALL2(struct Library *, &AROS_SLIB_ENTRY(OpenLibrary, Exec), \
263 AROS_LCA(STRPTR, libname, A1), \
264 AROS_LCA(ULONG, version, D0), \
265 struct ExecBase *, SysBase)
267 #define ExecOpenDevice(devname, unitNumber, iORequest, flags) \
268 AROS_CALL4(BYTE, &AROS_SLIB_ENTRY(OpenDevice, Exec), \
269 AROS_LCA(STRPTR, devname, A0), \
270 AROS_LCA(ULONG, unitNumber, D0), \
271 AROS_LCA(struct IORequest *, iORequest, A1), \
272 AROS_LCA(ULONG, flags, D1), \
273 struct ExecBase *, SysBase)
276 struct LDObjectNode
278 struct Node ldon_Node;
279 struct SignalSemaphore ldon_SigSem;
280 ULONG ldon_AccessCount;
281 #if CHECK_DEPENDENCY
282 struct Task *ldon_FirstLocker;
283 #endif
286 struct LDObjectNode *LDNewObjectNode(STRPTR name, struct DosLibrary *DOSBase)
288 struct ExecBase *SysBase = DOSBase->dl_SysBase;
290 struct LDObjectNode *ret = AllocVec(sizeof(struct LDObjectNode), MEMF_ANY);
291 if (ret)
293 ULONG len = strlen(name);
294 STRPTR dupname = AllocVec(len+1, MEMF_ANY);
295 if (dupname)
297 CopyMem(name, dupname, len);
298 dupname[len] = '\0';
299 ret->ldon_Node.ln_Name = dupname;
300 InitSemaphore(&ret->ldon_SigSem);
301 ret->ldon_AccessCount = 0;
303 #if CHECK_DEPENDENCY
304 ret->ldon_FirstLocker = FindTask(0);
305 #endif
307 return ret;
309 FreeVec(ret);
312 return NULL;
315 VOID LDDestroyObjectNode(struct LDObjectNode *object, struct DosLibrary *DOSBase)
317 struct ExecBase *SysBase = DOSBase->dl_SysBase;
319 FreeVec(object->ldon_Node.ln_Name);
320 FreeVec(object);
323 AROS_LH2(struct Library *, OpenLibrary,
324 AROS_LHA(STRPTR, libname, A1),
325 AROS_LHA(ULONG, version, D0),
326 struct ExecBase *, SysBase, 0, Dos)
328 AROS_LIBFUNC_INIT
330 struct DosLibrary *DOSBase = SysBase->ex_RamLibPrivate;
331 struct Library *library, *tmplib;
332 STRPTR stripped_libname;
333 struct LDObjectNode *object;
336 We get the DOS semaphore to prevent the following:
337 - task 1 tries to open foobar.library, needs to load it from disk...
338 - task 1 Permit()'s (since its not doing list things)
339 - task switch (whilst LDDemon MAY get process next it might not)
340 - task 2 tries to open foobar.library, needs to load it from disk...
341 - it also requests LDDemon to open foobar.library, so it is now
342 trying to open it twice
344 We block all OpenLibrary() callers from searching the list until
345 all the other OpenLibrary() callers have returned. That way,
346 task #2 won't ask for foobar.library until task #1 has got its
347 response back from the LDDemon process.
349 falemagn: I changed the implementation of all that.
350 There's a list of "LDObjectNodes", that contain the name
351 of the object being opened. Since the problem is that more
352 processes can attempt to open the same device/library Instead of
353 locking a global semaphore until the opening is done, we lock a
354 per-object semaphore, so that others libraries/devices can be opened
355 in the meantime. Before a deadlock could happen if there was a
356 situation like this:
358 Process A opens L --------> LDDemon loads L and locks sem S
361 1 / \ 3
363 / 2 \
364 L spawns a process B and ----------> The process opens
365 waits for it to respond a library but gets loked
366 to a message <----/---- because sem S is locked
370 Proces B will never
371 respond to L.
373 Hopefully this won't happen anymore now.
377 /* We use FilePart() because the liblist is built from resident IDs,
378 and contain no path. Eg. The user can request gadgets/foo.gadget,
379 but the resident only contains foo.gadget
381 stripped_libname = FilePart(libname);
382 ObtainSemaphore(&DOSBase->dl_LDObjectsListSigSem);
383 object = (struct LDObjectNode *)FindName(&DOSBase->dl_LDObjectsList, stripped_libname);
384 if (!object)
386 object = LDNewObjectNode(stripped_libname, DOSBase);
387 if (object)
389 AddTail(&DOSBase->dl_LDObjectsList, (struct Node *)object);
393 if (object)
395 object->ldon_AccessCount += 1;
397 #if CHECK_DEPENDENCY
398 else
400 struct Task *curtask = FindTask(0);
401 struct ETask *et = GetETask(curtask);
403 D(bug("Checking for circular dependency\n"));
404 if (et)
406 while (curtask && curtask != object->ldon_FirstLocker)
407 curtask = et->et_Parent;
409 if (curtask)
411 bug("Circular dependency found!\n");
412 object = NULL;
416 #endif
417 ReleaseSemaphore(&DOSBase->dl_LDObjectsListSigSem);
419 if (!object)
420 return NULL;
423 ObtainSemaphore(&object->ldon_SigSem);
425 /* Call the EXEC's OpenLibrary function */
426 library = ExecOpenLibrary(stripped_libname, version);
428 if( library == NULL )
430 /* Use stack for now, this could be a security hole */
431 struct LDDMsg ldd;
433 ldd.ldd_ReplyPort.mp_SigBit = SIGB_SINGLE;
434 ldd.ldd_ReplyPort.mp_SigTask = FindTask(NULL);
435 NEWLIST(&ldd.ldd_ReplyPort.mp_MsgList);
436 ldd.ldd_ReplyPort.mp_Flags = PA_SIGNAL;
437 ldd.ldd_ReplyPort.mp_Node.ln_Type = NT_MSGPORT;
439 ldd.ldd_Msg.mn_Node.ln_Type = NT_MESSAGE;
441 ldd.ldd_Msg.mn_Length = sizeof(struct LDDMsg);
442 ldd.ldd_Msg.mn_ReplyPort = &ldd.ldd_ReplyPort;
444 ldd.ldd_Name = libname;
445 ldd.ldd_Version = version;
446 ldd.ldd_BaseDir = "libs";
448 SetSignal(0, SIGF_SINGLE);
449 D(bug("[LDCaller] Sending request for %s v%ld\n", libname, version));
450 PutMsg(DOSBase->dl_LDDemonPort, (struct Message *)&ldd);
451 WaitPort(&ldd.ldd_ReplyPort);
452 D(bug("[LDCaller] Returned\n"));
454 library = LDInit(ldd.ldd_Return, DOSBase);
456 if( library != NULL )
459 We have to Forbid() here because we need to look through the list
460 again, we also need to call the libOpen vector, which wants us
461 under a Forbidden state.
463 falemagn: well, it doesn't want us under a Forbidden state, it just
464 wants to be single threaded, and it is, in fact, so no
465 need for Forbid()/Permit() around open. I Hope... :)
468 Forbid();
469 tmplib = (struct Library *)FindName(&SysBase->LibList, stripped_libname);
470 Permit();
472 if( tmplib != NULL )
473 library = tmplib;
475 if(library->lib_Version >= version)
477 D(bug("[LDCaller] Calling libOpen() of %s\n",
478 library->lib_Node.ln_Name));
480 library = AROS_LVO_CALL1(struct Library *,
481 AROS_LCA(ULONG, version, D0),
482 struct Library *, library, 1,
485 D(bug("[LDCaller] libOpen() returned\n"));
487 else
488 library = NULL;
492 if (library == NULL)
495 the library is not on disk so
496 check Resident List
499 struct Resident *resident;
501 resident = FindResident(stripped_libname);
502 if (resident)
504 if (resident->rt_Version >= version)
506 if (InitResident(resident, NULL))
507 library = ExecOpenLibrary(stripped_libname, version);
513 Release the semaphore here, after calling Open vector. This
514 means that library open is singlethreaded by the semaphore.
515 It also handles circular dependant libraries. (Won't deadlock),
516 and recursive OpenLibrary calls (Semaphores nest when obtained
517 several times in a row by the same task).
519 ObtainSemaphore(&DOSBase->dl_LDObjectsListSigSem);
520 if (--(object->ldon_AccessCount) == 0)
522 Remove((struct Node *)object);
523 LDDestroyObjectNode(object, DOSBase);
525 else
526 ReleaseSemaphore(&object->ldon_SigSem);
527 ReleaseSemaphore(&DOSBase->dl_LDObjectsListSigSem);
529 return library;
531 AROS_LIBFUNC_EXIT
534 AROS_LH4(BYTE, OpenDevice,
535 AROS_LHA(STRPTR, devname, A0),
536 AROS_LHA(ULONG, unitNumber, D0),
537 AROS_LHA(struct IORequest *, iORequest, A1),
538 AROS_LHA(ULONG, flags, D1),
539 struct ExecBase *, SysBase, 0, Dos)
541 AROS_LIBFUNC_INIT
543 struct DosLibrary *DOSBase = SysBase->ex_RamLibPrivate;
544 struct Device *tmpdev;
545 STRPTR stripped_devname;
546 struct LDObjectNode *object;
548 iORequest->io_Error = IOERR_OPENFAIL;
549 iORequest->io_Device = NULL;
551 /* We use FilePart() because the liblist is built from resident IDs,
552 which contain no path. Eg. The user can request gadgets/foo.gadget,
553 but the resident only contains foo.gadget
556 stripped_devname = FilePart(devname);
558 ObtainSemaphore(&DOSBase->dl_LDObjectsListSigSem);
559 object = (struct LDObjectNode *)FindName(&DOSBase->dl_LDObjectsList, stripped_devname);
561 if (!object)
563 object = LDNewObjectNode(stripped_devname, DOSBase);
564 if (object)
566 AddTail(&DOSBase->dl_LDObjectsList, (struct Node*)object);
570 if (object)
572 object->ldon_AccessCount += 1;
574 #if CHECK_DEPENDENCY
575 else
577 struct Task *curtask = FindTask(0);
578 struct ETask *et = GetETask(curtask);
580 if (et)
582 while (curtask && curtask != object->ldon_FirstLocker)
583 curtask = et->et_Parent;
585 if (curtask)
587 bug("[LDCaller] Circular dependency found!\n");
588 object = NULL;
592 #endif
593 ReleaseSemaphore(&DOSBase->dl_LDObjectsListSigSem);
595 if (!object)
596 return IOERR_OPENFAIL;
598 ObtainSemaphore(&object->ldon_SigSem);
600 ExecOpenDevice(stripped_devname, unitNumber, iORequest, flags);
602 if (iORequest->io_Error)
604 /* Use stack for now, this could be a security hole */
605 struct LDDMsg ldd;
607 ldd.ldd_ReplyPort.mp_SigBit = SIGB_SINGLE;
608 ldd.ldd_ReplyPort.mp_SigTask = FindTask(NULL);
609 NEWLIST(&ldd.ldd_ReplyPort.mp_MsgList);
610 ldd.ldd_ReplyPort.mp_Flags = PA_SIGNAL;
611 ldd.ldd_ReplyPort.mp_Node.ln_Type = NT_MSGPORT;
613 ldd.ldd_Msg.mn_Node.ln_Type = NT_MESSAGE;
614 ldd.ldd_Msg.mn_Length = sizeof(struct LDDMsg);
615 ldd.ldd_Msg.mn_ReplyPort = &ldd.ldd_ReplyPort;
617 ldd.ldd_Name = devname;
618 ldd.ldd_BaseDir = "devs";
620 SetSignal(0, SIGF_SINGLE);
621 D(bug("[LDCaller] Sending request for %s\n", devname));
622 PutMsg(DOSBase->dl_LDDemonPort, (struct Message *)&ldd);
623 WaitPort(&ldd.ldd_ReplyPort);
624 D(bug("[LDCaller] Returned\n"));
626 iORequest->io_Device = (struct Device *)LDInit(ldd.ldd_Return, DOSBase);
628 if(iORequest->io_Device)
630 Forbid();
631 tmpdev = (struct Device *)FindName(&SysBase->DeviceList, stripped_devname);
632 Permit();
634 if(tmpdev != NULL)
635 iORequest->io_Device = tmpdev;
637 iORequest->io_Error = 0;
638 iORequest->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
640 D(bug("[LDCaller] Calling devOpen() of %s unit %ld\n",
641 iORequest->io_Device->dd_Library.lib_Node.ln_Name, unitNumber));
643 AROS_LVO_CALL3NR(void,
644 AROS_LCA(struct IORequest *, iORequest, A1),
645 AROS_LCA(ULONG, unitNumber, D0),
646 AROS_LCA(ULONG, flags, D1),
647 struct Device *, iORequest->io_Device, 1,
650 D(bug("[LDCaller] devOpen() returned\n"));
652 if (iORequest->io_Error)
653 iORequest->io_Device = NULL;
657 ObtainSemaphore(&DOSBase->dl_LDObjectsListSigSem);
658 if (--(object->ldon_AccessCount) == 0)
660 Remove((struct Node *)object);
661 LDDestroyObjectNode(object, DOSBase);
663 else
664 ReleaseSemaphore(&object->ldon_SigSem);
665 ReleaseSemaphore(&DOSBase->dl_LDObjectsListSigSem);
667 D(bug("%s", iORequest->io_Error?"[LDCaller] Couldn't open the device\n":""));
669 return iORequest->io_Error;
671 AROS_LIBFUNC_EXIT
674 AROS_LH1(void, CloseLibrary,
675 AROS_LHA(struct Library *, library, A1),
676 struct ExecBase *, SysBase, 0, Dos)
678 AROS_LIBFUNC_INIT
680 struct DosLibrary *DOSBase = SysBase->ex_RamLibPrivate;
681 BPTR seglist;
683 if( library != NULL )
685 Forbid();
686 seglist = AROS_LVO_CALL0(BPTR, struct Library *, library, 2, );
687 if( seglist )
689 DOSBase->dl_LDReturn = MEM_TRY_AGAIN;
691 /* Safe to call from a Task */
692 UnLoadSeg(seglist);
694 Permit();
697 AROS_LIBFUNC_EXIT
700 AROS_LH1(void, CloseDevice,
701 AROS_LHA(struct IORequest *, iORequest, A1),
702 struct ExecBase *, SysBase, 0, Dos)
704 AROS_LIBFUNC_INIT
705 struct DosLibrary *DOSBase = SysBase->ex_RamLibPrivate;
706 BPTR seglist = NULL;
708 Forbid();
709 if( iORequest->io_Device != NULL )
711 seglist = AROS_LVO_CALL1(BPTR,
712 AROS_LCA(struct IORequest *, iORequest, A1),
713 struct Device, iORequest->io_Device, 2, );
714 iORequest->io_Device=(struct Device *)-1;
715 if( seglist )
717 DOSBase->dl_LDReturn = MEM_TRY_AGAIN;
718 UnLoadSeg(seglist);
721 Permit();
722 AROS_LIBFUNC_EXIT
725 AROS_LH1(void, RemLibrary,
726 AROS_LHA(struct Library *, library, A1),
727 struct ExecBase *, SysBase, 0, Dos)
729 AROS_LIBFUNC_INIT
731 struct DosLibrary *DOSBase = SysBase->ex_RamLibPrivate;
732 BPTR seglist;
734 Forbid();
735 /* calling ExpungeLib: library ends up in D0 and A6 for compatibility */
736 seglist = AROS_CALL1(BPTR, __AROS_GETVECADDR(library, 3),
737 AROS_LCA(struct Library *, library, D0),
738 struct Library *, library
740 if( seglist )
742 DOSBase->dl_LDReturn = MEM_TRY_AGAIN;
743 UnLoadSeg(seglist);
745 Permit();
747 AROS_LIBFUNC_EXIT
750 AROS_UFH3(LONG, LDFlush,
751 AROS_UFHA(struct MemHandlerData *, lmhd, A0),
752 AROS_UFHA(APTR, data, A1),
753 AROS_UFHA(struct ExecBase *, SysBase, A6)
756 AROS_USERFUNC_INIT
758 struct DosLibrary *DOSBase = SysBase->ex_RamLibPrivate;
759 struct Library *library;
761 D(bug("[LDDemon] Flush called\n"));
762 DOSBase->dl_LDReturn = MEM_DID_NOTHING;
764 /* Forbid() is already done, but I don't want to rely on it. */
765 Forbid();
767 /* Follow the linked list of shared libraries. */
768 library = (struct Library *)SysBase->LibList.lh_Head;
769 while(library->lib_Node.ln_Succ != NULL)
771 /* Flush libraries with a 0 open count */
772 if( ! library->lib_OpenCnt )
774 /* the library list node will be wiped from memory */
775 struct Library *nextLib = (struct Library *)library->lib_Node.ln_Succ;
776 RemLibrary(library);
777 /* Did it really go away? */
778 if( DOSBase->dl_LDReturn != MEM_DID_NOTHING )
780 /* Yes! Return it. */
781 Permit();
782 return MEM_TRY_AGAIN;
784 library = nextLib;
786 else
788 /* Go on to next library. */
789 library = (struct Library *)library->lib_Node.ln_Succ;
793 /* Do the same with the device list. */
794 library = (struct Library *)SysBase->DeviceList.lh_Head;
795 while(library->lib_Node.ln_Succ != NULL)
797 /* Flush libraries with a 0 open count */
798 if( ! library->lib_OpenCnt )
800 struct Library *nextDev = (struct Library *)library->lib_Node.ln_Succ;
801 RemDevice((struct Device *)library);
802 /* Did it really go away? */
803 if( DOSBase->dl_LDReturn != MEM_DID_NOTHING )
805 /* Yes! Return it. */
806 Permit();
807 return MEM_TRY_AGAIN;
809 library = nextDev;
811 else
813 /* Go on to next library. */
814 library = (struct Library *)library->lib_Node.ln_Succ;
817 Permit();
818 return MEM_DID_NOTHING;
820 AROS_USERFUNC_EXIT
824 void LDDemon()
825 The LDDemon process entry. Sits around and does nothing until a
826 request for a library comes, when it will then find the library
827 and hopefully open it.
829 AROS_UFH3(void, LDDemon,
830 AROS_UFHA(STRPTR, argstr, A0),
831 AROS_UFHA(ULONG, arglen, D0),
832 AROS_UFHA(struct ExecBase *, SysBase, A6)
835 AROS_USERFUNC_INIT
837 struct DosLibrary *DOSBase = SysBase->ex_RamLibPrivate;
838 struct LDDMsg *ldd;
840 for(;;)
842 WaitPort(DOSBase->dl_LDDemonPort);
843 while( (ldd = (struct LDDMsg *)GetMsg(DOSBase->dl_LDDemonPort)) )
845 D(bug("[LDDemon] Got a request for %s in %s\n",
846 ldd->ldd_Name, ldd->ldd_BaseDir));
848 ldd->ldd_Return = LDLoad(
849 ldd->ldd_ReplyPort.mp_SigTask,
850 ldd->ldd_Name,
851 ldd->ldd_BaseDir,
852 DOSBase);
854 D(bug("[LDDemon] Replying with %p as result\n", ldd->ldd_Return));
855 ReplyMsg((struct Message *)ldd);
856 } /* messages available */
859 AROS_USERFUNC_EXIT
862 AROS_UFH3(ULONG, AROS_SLIB_ENTRY(Init, LDDemon),
863 AROS_UFHA(ULONG, dummy, D0),
864 AROS_UFHA(BPTR, segList, A0),
865 AROS_UFHA(struct ExecBase *, sysBase, A6)
868 AROS_USERFUNC_INIT
870 struct DosLibrary *DOSBase;
871 struct TagItem tags[] =
873 { NP_Entry, (IPTR)LDDemon },
874 { NP_Input, 0 },
875 { NP_Output, 0 },
876 { NP_WindowPtr, -1 },
877 { NP_Name, (IPTR)ldDemonName },
878 { NP_StackSize, AROS_STACKSIZE },
879 { TAG_END , 0 }
882 /* We want version v41 of DOS, since it corresponds to AROS atm... */
883 if((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 41)) == NULL)
885 Alert(AT_DeadEnd | AN_RAMLib | AG_OpenLib | AO_DOSLib);
888 SysBase->ex_RamLibPrivate = DOSBase;
890 if( (DOSBase->dl_LDDemonPort = CreateMsgPort()) == NULL )
892 Alert( AN_RAMLib | AG_NoMemory | AT_DeadEnd );
895 FreeSignal(DOSBase->dl_LDDemonPort->mp_SigBit);
896 DOSBase->dl_LDDemonPort->mp_SigBit = SIGBREAKB_CTRL_F;
898 DOSBase->dl_LDHandler.is_Node.ln_Name = (STRPTR)ldDemonName;
899 DOSBase->dl_LDHandler.is_Node.ln_Pri = 0;
900 DOSBase->dl_LDHandler.is_Code = (void (*)())LDFlush;
901 DOSBase->dl_LDHandler.is_Data = NULL;
903 NEWLIST(&DOSBase->dl_LDObjectsList);
904 InitSemaphore(&DOSBase->dl_LDObjectsListSigSem);
905 AddMemHandler(&DOSBase->dl_LDHandler);
908 * Grab the semaphore ourself. The reason for this is that it will
909 * cause all other tasks to wait until we have finished initialising
910 * before they try and open something.
912 ObtainSemaphore(&DOSBase->dl_LDObjectsListSigSem);
914 #define SetFunc(offs,ptr) \
915 SetFunction(&SysBase->LibNode, (offs)*LIB_VECTSIZE, \
916 AROS_SLIB_ENTRY(ptr,Dos))
918 /* Do not set the vectors until you have initialised everything else. */
919 __OpenLibrary = SetFunc(-92, OpenLibrary);
920 __OpenDevice = SetFunc(-74, OpenDevice);
921 (void)SetFunc(-69, CloseLibrary);
922 (void)SetFunc(-75, CloseDevice);
923 (void)SetFunc(-67, RemLibrary);
924 (void)SetFunc(-73, RemLibrary);
926 if( !(DOSBase->dl_LDDemonTask = CreateNewProc((struct TagItem *)tags)) )
928 Alert( AT_DeadEnd | AN_RAMLib | AG_ProcCreate );
931 /* Fix up the MsgPort */
933 DOSBase->dl_LDDemonPort->mp_SigTask = DOSBase->dl_LDDemonTask;
935 /* Then unlock the semaphore to allow other processes to run. */
936 ReleaseSemaphore(&DOSBase->dl_LDObjectsListSigSem);
938 return 0;
940 AROS_USERFUNC_EXIT
943 const int LIBEND TEXT_SECTION = 1;