/* Library.c * Routines required in all shared libraries. * Copyright 1986 by James M Synge. */ #include "exec/types.h" #include "exec/libraries.h" #include "ExtLibrary.h" #include "libraries/dos.h" /* Declare the name of the library */ char LibraryName[] = "task.library"; char LibraryId[] = "task.library V1.0 (25 May 1987)\015\012"; #define LIB_VERSION 1 #define LIB_REVISION 2 /* * This short assembler section is included here so that * there is just one small place where these numbers need to * be replaced, instead of in two different files (i.e. here * and LibHead.asm). */ #asm PUBLIC LibVersion PUBLIC LibRevision LibVersion EQU 1 ; Shared with libhead via LibRevision EQU 2 ; the PUBLIC statement #endasm /* * If the rt_Flags field of the RomTag (struct Resident) has * the AUTOINIT bit set, then the rt_Init field must point * to a block such the following LibInitBlock. This block * contains four of the five parameters which OpenLibrary() * will pass to MakeLibrary. (The fifth parameter is the * SegList.) If the AUTOINIT bit is not set, then the * rt_Init field must point to a routine which will perform * the equivalent initialization. * * When the library is being auto-initialized, a block of * memory is allocated by MakeLibrary(). Its size is * determined by the length of FunctionList (in Functions.c) * and an entry, lib_sizeof_ExtLibrary, in the structure * pointed to by rt_Init. That entry is the size in bytes * of the struct ExtLibrary to be allocated automatically, * before calling the routine whose address is in * lib_InitCode. So, this value must be known before * linking. * * This can be done by expressing the LibInitBlock structure * in C so that the compiler can determine the size for us. * This is a drastic improvement over figuring it out by * hand! */ extern long *FunctionList[]; void _LibInitCode(); struct { long lib_sizeof_ExtLibrary; /* Bytes to allocate */ APTR lib_FunctionList; /* Ptr to func list */ long lib_InitStruct; /* see initializers.i */ APTR lib_InitCode; /* Ptr to asm routine */ } LibInitBlock = { sizeof( struct ExtLibrary ), (APTR) FunctionList, 0L, /* No struct init */ (APTR) _LibInitCode }; /* The assembly routine _LibInitCode calls LibraryInit() to * complete the initialization of the library. */ struct ExtLibrary * LibraryInit( LibBasePtr ) struct ExtLibrary *LibBasePtr; { /* These initializations are done here because it is * difficult to build an initializer structure with * Aztec Assembler 3.2. The argument, the library * pointer, is pushed onto the stack by the * assembler routine _LibInitCode. */ LibBasePtr -> el_Node.ln_Type = NT_LIBRARY; LibBasePtr -> el_Node.ln_Name = LibraryName; LibBasePtr -> el_Version = LIB_VERSION; LibBasePtr -> el_Revision = LIB_REVISION; LibBasePtr -> el_IdString = (APTR) LibraryId; /* Now set up the initial values for my libraries' * variables. */ /* NONE IN THIS EXAMPLE!!! */ return LibBasePtr; /* This is the value which * will be returned to * MakeLibrary() */ } /* * The required routines Open, Close and Expunge are called * not by other C routines, but rather by Exec. This means * that their arguments are in registers instead of on the * stack. * * There are three straight forward options at this point: * * 1) Use the variable LibraryBase (see LibHead.asm) which * should contain the same value as that in A6. * * 2) Immediately call the routine regA6() in LibHead.asm * which will return the value in A6 (Should be the * Library Base Pointer). This requires that we can be * certain that A6 hasn't been wiped out already by the * compiler generated setup code. * * 3) Place an intermediate assembly routine between exec * and each C routine which moves the arguments, * including the Library Base Pointer, from the * registers to the stack. * * The last method seems the best, so we'll use it. */ struct ExtLibrary * Library_Open( LibBasePtr, Version ) struct ExtLibrary *LibBasePtr; /* Was in A6 */ long Version; /* Was in D0 */ { Forbid(); /* Note that another open has occured. */ LibBasePtr->el_OpenCnt ++; /* Since we know that there is at least one user of * this library, we'll ignore any previous call to * Library_Expunge. */ LibBasePtr->el_Flags &= ~LIBF_DELEXP; Permit(); return LibBasePtr; } /* When the memory allocator in exec.library is looking for * more memory, it will try to get rid of the memory used by * libraries, devices and fonts. To do this with a library, * it calls Library_Expunge, the third of the required * routines. If Library_Expunge returns zero, then the * memory allocator looks elsewhere. If it returns non-zero * then the value must be a pointer to an AmigaDOS SegList. * This will be placed on the free list by the memory * allocator. It is the responsibility of the library to * free the jump table and Library structure. */ extern BPTR LibSegList; /* Allocated in LibHead.asm */ BPTR Library_Expunge( LibBasePtr ) struct ExtLibrary * LibBasePtr; /* Was in A6 */ { unsigned long size, JumpTableBase; /* The memory allocator runs inside a Forbid() / * Permit() pair. To protect against being called * by somebody else (i.e. Library_Close). */ Forbid (); if (LibBasePtr->el_OpenCnt > 0) { /* Still open, so note the expunge for * later use in Library_Close. */ LibBasePtr->el_Flags |= LIBF_DELEXP; Permit (); return 0; } /* Remove the library from the exec library list * so that nobody tries to allocate the library. */ Remove( LibBasePtr ); /* Now free up the jump table and library structure. * We add the sizes of the two (lib_NegSize is the * size of the jump table, and lib_PosSize is the * size of struct ExtLibrary), then free the block * starting at the base of the jump table. */ size = (long)(LibBasePtr->el_NegSize) + (long)(LibBasePtr->el_PosSize); if ( size ) { JumpTableBase = (long) LibBasePtr - (long) (LibBasePtr->el_NegSize); FreeMem( JumpTableBase, size ); } Permit(); return LibSegList; } /* When the exec routine CloseLibrary() is called, it calls * the required Close() routine of the identified library. * That routine is implemented here by Library_Close. It * decrements the open count. If it is zero, and if the * delayed expunge flags is set, then Library_Expunge() is * called. Just as in the case of the Expunge routine, if * a non-zero value is returned, it must be a BPTR to an * AmigaDOS SegList. */ BPTR Library_Close( LibBasePtr ) struct ExtLibrary * LibBasePtr; /* Was in A6 */ { Forbid(); /* Have to be cautious when there's * not much documentation. */ LibBasePtr->el_OpenCnt -- ; /* Decrement */ Permit(); if (LibBasePtr->el_OpenCnt == 0) if ((LibBasePtr->el_Flags & LIBF_DELEXP) != 0) return Library_Expunge(); return 0; /* No expunge. */ } /* Now for the big routine! */ long Library_Reserved() { return(0L); }