|
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 |
|