|
- /*********************************************************************
- * Universal NetWare library stub. *
- * written by Ulrich Neuman and given to OpenSource copyright-free. *
- * Extended for CLIB support by Guenter Knauf. *
- *********************************************************************/
-
- #ifdef NETWARE /* Novell NetWare */
-
- #include <stdlib.h>
-
- #ifdef __NOVELL_LIBC__
- /* For native LibC-based NLM we need to register as a real lib. */
- #include <errno.h>
- #include <string.h>
- #include <library.h>
- #include <netware.h>
- #include <screen.h>
- #include <nks/thread.h>
- #include <nks/synch.h>
-
- typedef struct
- {
- int _errno;
- void *twentybytes;
- } libthreaddata_t;
-
- typedef struct
- {
- int x;
- int y;
- int z;
- void *tenbytes;
- NXKey_t perthreadkey; /* if -1, no key obtained... */
- NXMutex_t *lock;
- } libdata_t;
-
- int gLibId = -1;
- void *gLibHandle = (void *) NULL;
- rtag_t gAllocTag = (rtag_t) NULL;
- NXMutex_t *gLibLock = (NXMutex_t *) NULL;
-
- /* internal library function prototypes... */
- int DisposeLibraryData ( void * );
- void DisposeThreadData ( void * );
- int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata );
-
-
- int _NonAppStart( void *NLMHandle,
- void *errorScreen,
- const char *cmdLine,
- const char *loadDirPath,
- size_t uninitializedDataLength,
- void *NLMFileHandle,
- int (*readRoutineP)( int conn,
- void *fileHandle, size_t offset,
- size_t nbytes,
- size_t *bytesRead,
- void *buffer ),
- size_t customDataOffset,
- size_t customDataSize,
- int messageCount,
- const char **messages )
- {
- NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
-
- #ifndef __GNUC__
- #pragma unused(cmdLine)
- #pragma unused(loadDirPath)
- #pragma unused(uninitializedDataLength)
- #pragma unused(NLMFileHandle)
- #pragma unused(readRoutineP)
- #pragma unused(customDataOffset)
- #pragma unused(customDataSize)
- #pragma unused(messageCount)
- #pragma unused(messages)
- #endif
-
- /*
- ** Here we process our command line, post errors (to the error screen),
- ** perform initializations and anything else we need to do before being able
- ** to accept calls into us. If we succeed, we return non-zero and the NetWare
- ** Loader will leave us up, otherwise we fail to load and get dumped.
- */
- gAllocTag = AllocateResourceTag(NLMHandle,
- "<library-name> memory allocations", AllocSignature);
-
- if (!gAllocTag) {
- OutputToScreen(errorScreen, "Unable to allocate resource tag for "
- "library memory allocations.\n");
- return -1;
- }
-
- gLibId = register_library(DisposeLibraryData);
-
- if (gLibId < -1) {
- OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
- return -1;
- }
-
- gLibHandle = NLMHandle;
-
- gLibLock = NXMutexAlloc(0, 0, &liblock);
-
- if (!gLibLock) {
- OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
- return -1;
- }
-
- return 0;
- }
-
- /*
- ** Here we clean up any resources we allocated. Resource tags is a big part
- ** of what we created, but NetWare doesn't ask us to free those.
- */
- void _NonAppStop( void )
- {
- (void) unregister_library(gLibId);
- NXMutexFree(gLibLock);
- }
-
- /*
- ** This function cannot be the first in the file for if the file is linked
- ** first, then the check-unload function's offset will be nlmname.nlm+0
- ** which is how to tell that there isn't one. When the check function is
- ** first in the linked objects, it is ambiguous. For this reason, we will
- ** put it inside this file after the stop function.
- **
- ** Here we check to see if it's alright to ourselves to be unloaded. If not,
- ** we return a non-zero value. Right now, there isn't any reason not to allow
- ** it.
- */
- int _NonAppCheckUnload( void )
- {
- return 0;
- }
-
- int GetOrSetUpData(int id, libdata_t **appData, libthreaddata_t **threadData)
- {
- int err;
- libdata_t *app_data;
- libthreaddata_t *thread_data;
- NXKey_t key;
- NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
-
- err = 0;
- thread_data = (libthreaddata_t *) NULL;
-
- /*
- ** Attempt to get our data for the application calling us. This is where we
- ** store whatever application-specific information we need to carry in support
- ** of calling applications.
- */
- app_data = (libdata_t *) get_app_data(id);
-
- if (!app_data) {
- /*
- ** This application hasn't called us before; set up application AND per-thread
- ** data. Of course, just in case a thread from this same application is calling
- ** us simultaneously, we better lock our application data-creation mutex. We
- ** also need to recheck for data after we acquire the lock because WE might be
- ** that other thread that was too late to create the data and the first thread
- ** in will have created it.
- */
- NXLock(gLibLock);
-
- if (!(app_data = (libdata_t *) get_app_data(id))) {
- app_data = (libdata_t *) malloc(sizeof(libdata_t));
-
- if (app_data) {
- memset(app_data, 0, sizeof(libdata_t));
-
- app_data->tenbytes = malloc(10);
- app_data->lock = NXMutexAlloc(0, 0, &liblock);
-
- if (!app_data->tenbytes || !app_data->lock) {
- if (app_data->lock)
- NXMutexFree(app_data->lock);
-
- free(app_data);
- app_data = (libdata_t *) NULL;
- err = ENOMEM;
- }
-
- if (app_data) {
- /*
- ** Here we burn in the application data that we were trying to get by calling
- ** get_app_data(). Next time we call the first function, we'll get this data
- ** we're just now setting. We also go on here to establish the per-thread data
- ** for the calling thread, something we'll have to do on each application
- ** thread the first time it calls us.
- */
- err = set_app_data(gLibId, app_data);
-
- if (err) {
- free(app_data);
- app_data = (libdata_t *) NULL;
- err = ENOMEM;
- }
- else {
- /* create key for thread-specific data... */
- err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
-
- if (err) /* (no more keys left?) */
- key = -1;
-
- app_data->perthreadkey = key;
- }
- }
- }
- }
-
- NXUnlock(gLibLock);
- }
-
- if (app_data) {
- key = app_data->perthreadkey;
-
- if (key != -1 /* couldn't create a key? no thread data */
- && !(err = NXKeyGetValue(key, (void **) &thread_data))
- && !thread_data) {
- /*
- ** Allocate the per-thread data for the calling thread. Regardless of whether
- ** there was already application data or not, this may be the first call by a
- ** a new thread. The fact that we allocation 20 bytes on a pointer is not very
- ** important, this just helps to demonstrate that we can have arbitrarily
- ** complex per-thread data.
- */
- thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t));
-
- if (thread_data) {
- thread_data->_errno = 0;
- thread_data->twentybytes = malloc(20);
-
- if (!thread_data->twentybytes) {
- free(thread_data);
- thread_data = (libthreaddata_t *) NULL;
- err = ENOMEM;
- }
-
- if ((err = NXKeySetValue(key, thread_data))) {
- free(thread_data->twentybytes);
- free(thread_data);
- thread_data = (libthreaddata_t *) NULL;
- }
- }
- }
- }
-
- if (appData)
- *appData = app_data;
-
- if (threadData)
- *threadData = thread_data;
-
- return err;
- }
-
- int DisposeLibraryData( void *data )
- {
- if (data) {
- void *tenbytes = ((libdata_t *) data)->tenbytes;
-
- if (tenbytes)
- free(tenbytes);
-
- free(data);
- }
-
- return 0;
- }
-
- void DisposeThreadData( void *data )
- {
- if (data) {
- void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
-
- if (twentybytes)
- free(twentybytes);
-
- free(data);
- }
- }
-
- #else /* __NOVELL_LIBC__ */
- /* For native CLib-based NLM seems we can do a bit more simple. */
- #include <nwthread.h>
-
- int main ( void )
- {
- /* initialize any globals here... */
-
- /* do this if any global initializing was done
- SynchronizeStart();
- */
- ExitThread (TSR_THREAD, 0);
- return 0;
- }
-
- #endif /* __NOVELL_LIBC__ */
-
- #endif /* NETWARE */
-
|