Blame netware/nwlibc.c

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