revert between 56095 -> 55830 in arch
[AROS.git] / rom / lddemon / lddemon.c
blob303081d32e5f07065fee1e151e6c1c25116ce924
1 /*
2 Copyright © 1995-2019, The AROS Development Team. All rights reserved.
3 $Id$
5 Loader for shared libraries and devices.
6 */
8 #include <aros/config.h>
10 #include <aros/asmcall.h>
11 #include <aros/debug.h>
12 #include <aros/symbolsets.h>
13 #include <exec/execbase.h>
14 #include <exec/resident.h>
15 #include <exec/memory.h>
16 #include <exec/errors.h>
17 #include <exec/devices.h>
18 #include <exec/ports.h>
19 #include <exec/alerts.h>
20 #include <exec/tasks.h>
21 #include <dos/dos.h>
22 #include <dos/dosextens.h>
23 #include <dos/dostags.h>
24 #include <proto/exec.h>
25 #include <proto/execlock.h>
26 #include <proto/dos.h>
28 #include <proto/lddemon.h>
30 #include <resources/execlock.h>
31 #include <aros/types/spinlock_s.h>
33 #include <stddef.h>
34 #include <string.h>
36 #include "lddemon.h"
38 #ifdef __mc68000
39 #define INIT_IN_LDDEMON_CONTEXT 1
40 #else
41 #define INIT_IN_LDDEMON_CONTEXT 0
42 #endif
44 #define CHECK_DEPENDENCY 1
46 /* Please leave them here! They are needed on Linux-M68K */
47 AROS_LD2(struct Library *, OpenLibrary,
48 AROS_LDA(STRPTR, libname, A1),
49 AROS_LDA(ULONG, version, D0),
50 struct ExecBase *, SysBase, 0, Lddemon);
51 AROS_LD4(LONG, OpenDevice,
52 AROS_LDA(STRPTR, devname, A0),
53 AROS_LDA(IPTR, unitNumber, D0),
54 AROS_LDA(struct IORequest *, iORequest, A1),
55 AROS_LDA(ULONG, flags, D1),
56 struct ExecBase *, SysBase, 0, Lddemon);
57 AROS_LD1(void, CloseLibrary,
58 AROS_LDA(struct Library *, library, A1),
59 struct ExecBase *, SysBase, 0, Lddemon);
60 AROS_LD1(void, CloseDevice,
61 AROS_LDA(struct IORequest *, iORequest, A1),
62 struct ExecBase *, SysBase, 0, Lddemon);
63 AROS_LD1(void, RemLibrary,
64 AROS_LDA(struct Library *, library, A1),
65 struct ExecBase *, SysBase, 0, Lddemon);
67 struct LDDMsg
69 struct Message ldd_Msg; /* Message link */
70 struct MsgPort ldd_ReplyPort; /* Callers ReplyPort */
72 STRPTR ldd_Name; /* Name of thing to load */
74 STRPTR ldd_BaseDir; /* Base directory to load from */
75 #if INIT_IN_LDDEMON_CONTEXT
76 struct Library *ldd_Return; /* Loaded and initialized Library */
77 struct List *ldd_List; /* List to add */
78 #else
79 BPTR ldd_Return; /* Loaded seglist */
80 #endif
83 static const char ldDemonName[] = "Lib & Dev Loader Daemon";
86 overridable LoadSeg
88 AROS_LH1(BPTR, LDLoadSeg,
89 AROS_LHA(CONST_STRPTR, name, D1),
90 struct IntLDDemonBase *, ldBase, 1, Lddemon)
92 AROS_LIBFUNC_INIT
93 struct Library *DOSBase = ldBase->dl_DOSBase;
94 D(bug("[LDLoadSeg] name=%s\n", name));
95 return LoadSeg(name);
96 AROS_LIBFUNC_EXIT
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 LDLoad(struct IntLDDemonBase *ldBase, struct Process *caller, STRPTR name, STRPTR basedir, struct ExecBase *SysBase)
107 struct Process *me = (struct Process *)FindTask(NULL);
108 BPTR seglist = BNULL;
109 STRPTR path;
110 ULONG pathLen;
111 int delimPos;
114 If the caller was a process, we have more scope for loading
115 libraries. We can load them from the caller's current directory,
116 or from the PROGDIR: assign. These could both be the same
117 though.
119 D(bug(
120 "[LDLoad] caller=(%p) %s, name=%s, basedir=%s\n",
121 caller, caller->pr_Task.tc_Node.ln_Name, name, basedir
124 if (strncmp(name, "PROGDIR:", 8) == 0)
126 /* Special case for explicit PROGDIR-based path */
127 if (caller->pr_Task.tc_Node.ln_Type == NT_PROCESS)
129 if (caller->pr_HomeDir != BNULL)
131 BPTR oldHomeDir = me->pr_HomeDir;
132 D(bug("[LDLoad] Trying homedir\n"));
133 /* Temporarily override pr_HomeDir to let GetDeviceProc handle
134 PROGDIR: case correctly while opening library file */
135 me->pr_HomeDir = caller->pr_HomeDir;
136 seglist = LDLoadSeg(name);
137 me->pr_HomeDir = oldHomeDir;
141 else if (!strstr(name, ":")) {
142 delimPos = strlen(basedir);
143 pathLen = delimPos + strlen(name) + 2;
144 path = AllocMem(pathLen, MEMF_ANY);
145 if (path) {
146 strcpy(path, basedir);
147 path[delimPos] = '/';
148 strcpy(&path[delimPos + 1], name);
150 if (caller->pr_Task.tc_Node.ln_Type == NT_PROCESS)
152 /* Try the current directory of the caller */
154 D(bug("[LDLoad] Process\n"));
155 me->pr_CurrentDir = caller->pr_CurrentDir;
156 D(bug("[LDLoad] Trying currentdir\n"));
157 seglist = LDLoadSeg(name);
158 if ((!seglist) && path)
159 seglist = LDLoadSeg(path);
161 /* The the program directory of the caller */
162 if((!seglist) && (caller->pr_HomeDir != BNULL))
164 D(bug("[LDLoad] Trying homedir\n"));
165 me->pr_CurrentDir = caller->pr_HomeDir;
166 seglist = LDLoadSeg(name);
167 if ((!seglist) && path)
168 seglist = LDLoadSeg(path);
172 if (path) {
173 if (!seglist) {
174 /* Nup, let's try the default directory as supplied. */
175 D(bug("[LDLoad] Trying defaultdir\n"));
176 path[delimPos] = ':';
177 seglist = LDLoadSeg(path);
179 FreeMem(path, pathLen);
181 } else
182 seglist = LDLoadSeg(name);
184 return seglist;
188 Library *LDInit(seglist, DOSBase)
189 Initialise the library.
191 static struct Library *LDInit(BPTR seglist, struct List *list, STRPTR resname, struct ExecBase *SysBase)
193 struct Node *node = NULL;
194 BPTR seg = seglist;
196 /* we may not have any extension fields */
197 const int sizeofresident = offsetof(struct Resident, rt_Init) + sizeof(APTR);
199 while(seg)
201 STRPTR addr = (STRPTR)((IPTR)BADDR(seg) - sizeof(ULONG));
202 ULONG size = *(ULONG *)addr;
204 for(
205 addr += sizeof(BPTR) + sizeof(ULONG),
206 size -= sizeof(BPTR) + sizeof(ULONG);
207 size >= sizeofresident;
208 size -= 2, addr += 2
209 // size -= AROS_PTRALIGN, addr += AROS_PTRALIGN
212 struct Resident *res = (struct Resident *)addr;
213 if( res->rt_MatchWord == RTC_MATCHWORD
214 && res->rt_MatchTag == res )
216 D(bug("[LDInit] Calling InitResident(%p) on %s\n", res, res->rt_Name));
217 /* AOS compatibility requirement.
218 * Ramlib ignores InitResident() return code.
219 * After InitResident() it checks if lib/dev appeared
220 * in Exec lib/dev list via FindName().
222 * Evidently InitResident()'s return code was not
223 * reliable for some early AOS libraries.
225 Forbid();
226 InitResident(res, seglist);
227 node = FindName(list, res->rt_Name);
228 Permit();
229 D(bug("[LDInit] Done calling InitResident(%p) on %s, seg %p, node %p\n", res, res->rt_Name, BADDR(seglist), node));
231 return (struct Library*)node;
234 seg = *(BPTR *)BADDR(seg);
236 D(bug("[LDInit] Couldn't find Resident for %p\n", seglist));
237 #ifdef __mc68000
238 /* If struct Resident was not found, just run the code. SegList in A0.
239 * Required to load WB1.x devs:narrator.device. */
240 Forbid();
241 AROS_UFC1NR(void, BADDR(seglist) + sizeof(ULONG), AROS_UFCA(BPTR, seglist, A0));
242 node = FindName(list, resname);
243 Permit();
244 D(bug("[LDInit] Done direct calling %s, seg %p, node %p\n", resname, BADDR(seglist), node));
245 #endif
246 return (struct Library*)node;
249 static struct Library *CallLDInit(BPTR seglist, struct List *list, STRPTR resname, struct Library *DOSBase, struct ExecBase *SysBase)
251 struct Library *tmplib;
252 if (!seglist)
253 return NULL;
254 tmplib = LDInit(seglist, list, resname, SysBase);
255 if (!tmplib)
256 UnLoadSeg(seglist);
257 return tmplib;
260 #define ExecOpenLibrary(libname, version) \
261 AROS_CALL2(struct Library *, ldBase->__OpenLibrary, \
262 AROS_LCA(STRPTR, libname, A1), \
263 AROS_LCA(ULONG, version, D0), \
264 struct ExecBase *, SysBase)
266 #define ExecOpenDevice(devname, unitNumber, iORequest, flags) \
267 AROS_CALL4(LONG, ldBase->__OpenDevice, \
268 AROS_LCA(STRPTR, devname, A0), \
269 AROS_LCA(IPTR, unitNumber, D0), \
270 AROS_LCA(struct IORequest *, iORequest, A1), \
271 AROS_LCA(ULONG, flags, D1), \
272 struct ExecBase *, SysBase)
274 struct LDObjectNode
276 struct Node ldon_Node;
277 struct SignalSemaphore ldon_SigSem;
278 ULONG ldon_AccessCount;
279 #if CHECK_DEPENDENCY
280 struct Task *ldon_FirstLocker;
281 #endif
284 static struct LDObjectNode *LDNewObjectNode(STRPTR name, struct ExecBase *SysBase)
286 struct LDObjectNode *ret = AllocVec(sizeof(struct LDObjectNode), MEMF_ANY);
287 if (ret)
289 ULONG len = strlen(name);
290 STRPTR dupname = AllocVec(len+1, MEMF_ANY);
291 if (dupname)
293 CopyMem(name, dupname, len);
294 dupname[len] = '\0';
295 ret->ldon_Node.ln_Name = dupname;
296 InitSemaphore(&ret->ldon_SigSem);
297 ret->ldon_AccessCount = 0;
299 #if CHECK_DEPENDENCY
300 ret->ldon_FirstLocker = FindTask(0);
301 #endif
303 return ret;
305 FreeVec(ret);
308 return NULL;
311 static void ProcessLDMessage(struct IntLDDemonBase *ldBase, struct LDDMsg *ldd, struct ExecBase *SysBase);
313 static struct LDObjectNode *LDRequestObject(STRPTR libname, ULONG version, STRPTR dir, struct List *list, struct ExecBase *SysBase)
315 /* We use FilePart() because the liblist is built from resident IDs,
316 and contain no path. Eg. The user can request gadgets/foo.gadget,
317 but the resident only contains foo.gadget
319 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
320 #if defined(__AROSEXEC_SMP__)
321 void *ExecLockBase = ldBase->dl_ExecLockRes;
322 #endif
323 struct Library *DOSBase = ldBase->dl_DOSBase;
324 STRPTR stripped_libname = FilePart(libname);
325 struct Library *tmplib;
326 struct LDObjectNode *object;
328 D(bug("[LDDemon] %s()\n", __func__));
331 We get the DOS semaphore to prevent the following:
332 - task 1 tries to open foobar.library, needs to load it from disk...
333 - task 1 Permit()'s (since it's not doing list things)
334 - task switch (whilst LDDemon MAY get process next it might not)
335 - task 2 tries to open foobar.library, needs to load it from disk...
336 - it also requests LDDemon to open foobar.library, so it is now
337 trying to open it twice
339 We block all OpenLibrary() callers from searching the list until
340 all the other OpenLibrary() callers have returned. That way,
341 task #2 won't ask for foobar.library until task #1 has got its
342 response back from the LDDemon process.
344 falemagn: I changed the implementation of all that.
345 There's a list of "LDObjectNodes", that contain the name
346 of the object being opened. Since the problem is that more
347 processes can attempt to open the same device/library. Instead of
348 locking a global semaphore until the opening is done, we lock a
349 per-object semaphore, so that others libraries/devices can be opened
350 in the meantime. Before, a deadlock could happen if there was a
351 situation like this:
353 Process A opens L --------> LDDemon loads L and locks sem S
356 1 / \ 3
358 / 2 \
359 L spawns a process B and ----------> The process opens
360 waits for it to respond a library but gets loked
361 to a message <----/---- because sem S is locked
365 Proces B will never
366 respond to L.
368 Hopefully this won't happen anymore now.
370 ObtainSemaphore(&ldBase->dl_LDObjectsListSigSem);
372 object = (struct LDObjectNode *)FindName(&ldBase->dl_LDObjectsList, stripped_libname);
373 if (!object)
375 object = LDNewObjectNode(stripped_libname, SysBase);
376 if (object)
378 AddTail(&ldBase->dl_LDObjectsList, (struct Node *)object);
382 if (object)
384 object->ldon_AccessCount += 1;
387 ReleaseSemaphore(&ldBase->dl_LDObjectsListSigSem);
389 if (!object)
390 return NULL;
392 ObtainSemaphore(&object->ldon_SigSem);
394 /* Try to find the resident in the list */
395 #if defined(__AROSEXEC_SMP__)
396 ObtainSystemLock(list, SPINLOCK_MODE_READ, LOCKF_FORBID);
397 #endif
398 tmplib = (struct Library *)FindName(list, stripped_libname);
399 #if defined(__AROSEXEC_SMP__)
400 ReleaseSystemLock(list, LOCKF_FORBID);
401 #endif
403 if (!tmplib)
405 /* Try to load from disk if not found */
406 struct LDDMsg ldd;
407 bzero(&ldd, sizeof(ldd));
409 ldd.ldd_ReplyPort.mp_SigBit = SIGB_SINGLE;
410 ldd.ldd_ReplyPort.mp_SigTask = FindTask(NULL);
411 ldd.ldd_ReplyPort.mp_Flags = PA_SIGNAL;
412 ldd.ldd_ReplyPort.mp_Node.ln_Type = NT_MSGPORT;
414 NEWLIST(&ldd.ldd_ReplyPort.mp_MsgList);
416 ldd.ldd_Msg.mn_Node.ln_Type = NT_MESSAGE;
417 ldd.ldd_Msg.mn_Length = sizeof(struct LDDMsg);
418 ldd.ldd_Msg.mn_ReplyPort = &ldd.ldd_ReplyPort;
420 ldd.ldd_Name = libname;
421 ldd.ldd_BaseDir = dir;
422 #if INIT_IN_LDDEMON_CONTEXT
423 ldd.ldd_List = list;
424 #endif
426 D(bug("[LDCaller] Sending request for %s, InLDProcess %d\n",
427 stripped_libname, (struct Process*)FindTask(NULL) == ldBase->dl_LDDemonTask));
429 #if INIT_IN_LDDEMON_CONTEXT
430 /* Direct call if already in LDDemon context */
431 if ((struct Process*)FindTask(NULL) == ldBase->dl_LDDemonTask) {
432 ProcessLDMessage(ldBase, &ldd, SysBase);
433 } else
434 #endif
436 SetSignal(0, SIGF_SINGLE);
437 PutMsg(ldBase->dl_LDDemonPort, (struct Message *)&ldd);
438 WaitPort(&ldd.ldd_ReplyPort);
441 D(bug("[LDCaller] Returned 0x%p\n", ldd.ldd_Return));
443 #if INIT_IN_LDDEMON_CONTEXT
444 tmplib = ldd.ldd_Return;
445 #else
446 tmplib = CallLDInit(ldd.ldd_Return, list, stripped_libname, DOSBase, SysBase);
447 #endif
450 if (!tmplib)
453 * The library is not on disk so check Resident List.
454 * It can be there if it is resident but was flushed.
456 struct Resident *resident = FindResident(stripped_libname);
459 * Check if the resident is of required type and version is correct.
460 * This relies on the fact that lh_Type is set correctly for exec lists.
461 * In AROS this is true (see rom/exec/prepareexecbase.c).
463 if (resident && (resident->rt_Type == list->lh_Type) && (resident->rt_Version >= version))
464 InitResident(resident, BNULL);
467 return object;
470 static void LDReleaseObject(struct LDObjectNode *object, struct ExecBase *SysBase)
472 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
475 Release the semaphore here, after calling Open vector. This
476 means that library open is singlethreaded by the semaphore.
477 It also handles circular dependant libraries. (Won't deadlock),
478 and recursive OpenLibrary calls (Semaphores nest when obtained
479 several times in a row by the same task).
482 ObtainSemaphore(&ldBase->dl_LDObjectsListSigSem);
484 if (--(object->ldon_AccessCount) == 0)
486 Remove((struct Node *)object);
488 * CHECKME: In LDRequestObject() we obtain the object semaphore also on a new object.
489 * So shouldn't we release it here too ?
492 FreeVec(object->ldon_Node.ln_Name);
493 FreeVec(object);
495 else
496 ReleaseSemaphore(&object->ldon_SigSem);
498 ReleaseSemaphore(&ldBase->dl_LDObjectsListSigSem);
501 AROS_LH2(struct Library *, OpenLibrary,
502 AROS_LHA(STRPTR, libname, A1),
503 AROS_LHA(ULONG, version, D0),
504 struct ExecBase *, SysBase, 0, Lddemon)
506 AROS_LIBFUNC_INIT
508 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
509 struct Library *library;
510 struct LDObjectNode *object;
512 D(bug("[LDDemon] %s()\n", __func__));
514 object = LDRequestObject(libname, version, "libs", &SysBase->LibList, SysBase);
516 if (!object)
517 return NULL;
519 /* Call the EXEC's OpenLibrary function */
520 library = ExecOpenLibrary(object->ldon_Node.ln_Name, version);
522 LDReleaseObject(object, SysBase);
524 return library;
526 AROS_LIBFUNC_EXIT
529 AROS_LH4(LONG, OpenDevice,
530 AROS_LHA(STRPTR, devname, A0),
531 AROS_LHA(IPTR, unitNumber, D0),
532 AROS_LHA(struct IORequest *, iORequest, A1),
533 AROS_LHA(ULONG, flags, D1),
534 struct ExecBase *, SysBase, 0, Lddemon)
536 AROS_LIBFUNC_INIT
538 struct LDObjectNode *object;
539 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
541 D(bug("[LDDemon] %s()\n", __func__));
543 object = LDRequestObject(devname, 0, "devs", &SysBase->DeviceList, SysBase);
545 if (object)
547 /* Call exec.library/OpenDevice(), it will do the job */
548 ExecOpenDevice(object->ldon_Node.ln_Name, unitNumber, iORequest, flags);
549 LDReleaseObject(object, SysBase);
551 else
553 iORequest->io_Error = IOERR_OPENFAIL;
554 iORequest->io_Device = NULL;
555 iORequest->io_Unit = NULL;
558 D(bug("[LDCaller] Open result: %d\n", iORequest->io_Error));
560 return iORequest->io_Error;
562 AROS_LIBFUNC_EXIT
565 AROS_LH1(void, CloseLibrary,
566 AROS_LHA(struct Library *, library, A1),
567 struct ExecBase *, SysBase, 0, Lddemon)
569 AROS_LIBFUNC_INIT
571 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
572 struct Library *DOSBase = ldBase->dl_DOSBase;
573 BPTR seglist;
575 D(bug("[LDDemon] %s()\n", __func__));
577 if( library != NULL )
579 Forbid();
580 seglist = AROS_LVO_CALL0(BPTR, struct Library *, library, 2, );
581 if( seglist )
583 ldBase->dl_LDReturn = MEM_TRY_AGAIN;
585 /* Safe to call from a Task */
586 UnLoadSeg(seglist);
588 Permit();
591 AROS_LIBFUNC_EXIT
594 AROS_LH1(void, CloseDevice,
595 AROS_LHA(struct IORequest *, iORequest, A1),
596 struct ExecBase *, SysBase, 0, Lddemon)
598 AROS_LIBFUNC_INIT
599 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
600 struct Library *DOSBase = ldBase->dl_DOSBase;
601 BPTR seglist = BNULL;
603 D(bug("[LDDemon] %s()\n", __func__));
605 Forbid();
606 if( iORequest->io_Device != NULL )
608 seglist = AROS_LVO_CALL1(BPTR,
609 AROS_LCA(struct IORequest *, iORequest, A1),
610 struct Device *, iORequest->io_Device, 2, );
611 iORequest->io_Device=(struct Device *)-1;
612 if( seglist )
614 ldBase->dl_LDReturn = MEM_TRY_AGAIN;
615 UnLoadSeg(seglist);
618 Permit();
619 AROS_LIBFUNC_EXIT
622 AROS_LH1(void, RemLibrary,
623 AROS_LHA(struct Library *, library, A1),
624 struct ExecBase *, SysBase, 0, Lddemon)
626 AROS_LIBFUNC_INIT
628 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
629 struct Library *DOSBase = ldBase->dl_DOSBase;
630 BPTR seglist;
632 D(bug("[LDDemon] %s()\n", __func__));
634 Forbid();
635 /* calling ExpungeLib: library ends up in D0 and A6 for compatibility */
636 seglist = AROS_CALL1(BPTR, __AROS_GETVECADDR(library, 3),
637 AROS_LCA(struct Library *, library, D0),
638 struct Library *, library
640 if( seglist )
642 ldBase->dl_LDReturn = MEM_TRY_AGAIN;
643 UnLoadSeg(seglist);
645 Permit();
647 AROS_LIBFUNC_EXIT
650 AROS_UFH3(LONG, LDFlush,
651 AROS_UFHA(struct MemHandlerData *, lmhd, A0),
652 AROS_UFHA(APTR, data, A1),
653 AROS_UFHA(struct ExecBase *, SysBase, A6)
656 AROS_USERFUNC_INIT
658 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
659 #if defined(__AROSEXEC_SMP__)
660 void *ExecLockBase = ldBase->dl_ExecLockRes;
661 #endif
662 struct Library *library;
664 D(bug("[LDDemon] %s()\n", __func__));
665 ldBase->dl_LDReturn = MEM_DID_NOTHING;
667 /* Forbid() is already done, but I don't want to rely on it. */
668 Forbid();
669 #if defined(__AROSEXEC_SMP__)
670 ObtainSystemLock(&SysBase->LibList, SPINLOCK_MODE_WRITE, 0);
671 #endif
673 /* Follow the linked list of shared libraries. */
674 library = (struct Library *)SysBase->LibList.lh_Head;
675 while(library->lib_Node.ln_Succ != NULL)
677 /* Flush libraries with a 0 open count */
678 if( ! library->lib_OpenCnt )
680 /* the library list node will be wiped from memory */
681 struct Library *nextLib = (struct Library *)library->lib_Node.ln_Succ;
682 RemLibrary(library);
683 /* Did it really go away? */
684 if( ldBase->dl_LDReturn != MEM_DID_NOTHING )
686 /* Yes! Return it. */
687 #if defined(__AROSEXEC_SMP__)
688 ReleaseSystemLock(&SysBase->LibList, 0);
689 #endif
690 Permit();
691 return MEM_TRY_AGAIN;
693 library = nextLib;
695 else
697 /* Go on to next library. */
698 library = (struct Library *)library->lib_Node.ln_Succ;
701 #if defined(__AROSEXEC_SMP__)
702 ReleaseSystemLock(&SysBase->LibList, 0);
704 ObtainSystemLock(&SysBase->DeviceList, SPINLOCK_MODE_WRITE, 0);
705 #endif
706 /* Do the same with the device list. */
707 library = (struct Library *)SysBase->DeviceList.lh_Head;
708 while(library->lib_Node.ln_Succ != NULL)
710 /* Flush libraries with a 0 open count */
711 if( ! library->lib_OpenCnt )
713 struct Library *nextDev = (struct Library *)library->lib_Node.ln_Succ;
714 RemDevice((struct Device *)library);
715 /* Did it really go away? */
716 if( ldBase->dl_LDReturn != MEM_DID_NOTHING )
718 /* Yes! Return it. */
719 #if defined(__AROSEXEC_SMP__)
720 ReleaseSystemLock(&SysBase->DeviceList, 0);
721 #endif
722 Permit();
723 return MEM_TRY_AGAIN;
725 library = nextDev;
727 else
729 /* Go on to next library. */
730 library = (struct Library *)library->lib_Node.ln_Succ;
733 #if defined(__AROSEXEC_SMP__)
734 ReleaseSystemLock(&SysBase->DeviceList, 0);
735 #endif
736 Permit();
738 return MEM_DID_NOTHING;
740 AROS_USERFUNC_EXIT
743 static void ProcessLDMessage(struct IntLDDemonBase *ldBase, struct LDDMsg *ldd, struct ExecBase *SysBase)
745 #if INIT_IN_LDDEMON_CONTEXT
746 struct Library *DOSBase = ldBase->dl_DOSBase;
747 #endif
748 BPTR seglist;
749 D(bug("[LDDemon] Got a request for %s in %s\n", ldd->ldd_Name, ldd->ldd_BaseDir));
751 seglist = LDLoad(ldBase, ldd->ldd_ReplyPort.mp_SigTask, ldd->ldd_Name, ldd->ldd_BaseDir, SysBase);
753 #if INIT_IN_LDDEMON_CONTEXT
754 ldd->ldd_Return = CallLDInit(seglist, ldd->ldd_List, FilePart(ldd->ldd_Name), ldBase->dl_DOSBase, SysBase);
755 D(bug("[LDDemon] Replying with %p as result, seglist was %p\n", ldd->ldd_Return, seglist));
756 #else
757 ldd->ldd_Return = seglist;
758 D(bug("[LDDemon] Replying with %p as result\n", ldd->ldd_Return));
759 #endif
763 void LDDemon()
764 The LDDemon process entry. Sits around and does nothing until a
765 request for a library comes, when it will then find the library
766 and hopefully open it.
768 static AROS_PROCH(LDDemon, argptr, argsize, SysBase)
770 AROS_PROCFUNC_INIT
772 struct IntLDDemonBase *ldBase = SysBase->ex_RamLibPrivate;
773 struct LDDMsg *ldd;
775 for(;;)
777 WaitPort(ldBase->dl_LDDemonPort);
778 while( (ldd = (struct LDDMsg *)GetMsg(ldBase->dl_LDDemonPort)) )
780 ProcessLDMessage(ldBase, ldd, SysBase);
781 ReplyMsg((struct Message *)ldd);
782 } /* messages available */
785 /* lddemon died */
786 return 0;
788 AROS_PROCFUNC_EXIT
791 static ULONG LDDemon_Init(struct IntLDDemonBase *ldBase)
793 struct Library *DOSBase;
794 struct TagItem tags[] =
796 { NP_Entry, (IPTR)LDDemon },
797 { NP_Input, 0 },
798 { NP_Output, 0 },
799 { NP_WindowPtr, -1 },
800 { NP_Name, (IPTR)ldDemonName },
801 { NP_Priority, 5 },
802 { TAG_END , 0 }
805 DOSBase = TaggedOpenLibrary(TAGGEDOPEN_DOS);
806 if (!DOSBase) {
807 Alert( AN_RAMLib | AG_OpenLib | AO_DOSLib | AT_DeadEnd );
810 if ((ldBase->dl_LDDemonPort = CreateMsgPort()) == NULL )
812 Alert( AN_RAMLib | AG_NoMemory | AT_DeadEnd );
815 NEWLIST(&ldBase->dl_Flavours);
817 FreeSignal(ldBase->dl_LDDemonPort->mp_SigBit);
818 ldBase->dl_LDDemonPort->mp_SigBit = SIGBREAKB_CTRL_F;
820 ldBase->dl_LDHandler.is_Node.ln_Name = (STRPTR)ldDemonName;
821 ldBase->dl_LDHandler.is_Node.ln_Pri = 0;
822 ldBase->dl_LDHandler.is_Code = (VOID_FUNC)LDFlush;
823 ldBase->dl_LDHandler.is_Data = NULL;
825 ldBase->dl_DOSBase = DOSBase;
827 NEWLIST(&ldBase->dl_LDObjectsList);
828 InitSemaphore(&ldBase->dl_LDObjectsListSigSem);
830 SysBase->ex_RamLibPrivate = ldBase;
832 AddMemHandler(&ldBase->dl_LDHandler);
834 #if defined(__AROSEXEC_SMP__)
835 ldBase->dl_ExecLockRes = OpenResource("execlock.resource");
836 #endif
839 * Grab the semaphore ourself. The reason for this is that it will
840 * cause all other tasks to wait until we have finished initialising
841 * before they try and open something.
843 ObtainSemaphore(&ldBase->dl_LDObjectsListSigSem);
845 #define SetFunc(offs,ptr) \
846 SetFunction(&SysBase->LibNode, (-offs)*(LONG)LIB_VECTSIZE, \
847 AROS_SLIB_ENTRY(ptr,Lddemon,0))
849 /* Do not set the vectors until you have initialised everything else. */
850 ldBase->__OpenLibrary = SetFunc(92, OpenLibrary);
851 ldBase->__OpenDevice = SetFunc(74, OpenDevice);
852 (void)SetFunc(69, CloseLibrary);
853 (void)SetFunc(75, CloseDevice);
854 (void)SetFunc(67, RemLibrary);
855 (void)SetFunc(73, RemLibrary);
857 if( !(ldBase->dl_LDDemonTask = CreateNewProc((struct TagItem *)tags)) )
859 Alert( AT_DeadEnd | AN_RAMLib | AG_ProcCreate );
862 /* Fix up the MsgPort */
864 ldBase->dl_LDDemonPort->mp_SigTask = ldBase->dl_LDDemonTask;
866 /* Then unlock the semaphore to allow other processes to run. */
867 ReleaseSemaphore(&ldBase->dl_LDObjectsListSigSem);
869 return TRUE;
872 ADD2INITLIB(LDDemon_Init, 0)