1 /*********************************************************************
2 * Universal NetWare library stub. *
3 * written by Ulrich Neuman and given to OpenSource copyright-free. *
4 * Extended for CLIB support by Guenter Knauf. *
5 *********************************************************************/
6
7 #ifdef NETWARE /* Novell NetWare */
8
9 #include <stdlib.h>
10
11 #ifdef __NOVELL_LIBC__
12 /* For native LibC-based NLM we need to register as a real lib. */
13 #include <errno.h>
14 #include <string.h>
15 #include <library.h>
16 #include <netware.h>
17 #include <screen.h>
18 #include <nks/thread.h>
19 #include <nks/synch.h>
20
21 typedef struct
22 {
23 int _errno;
24 void *twentybytes;
25 } libthreaddata_t;
26
27 typedef struct
28 {
29 int x;
30 int y;
31 int z;
32 void *tenbytes;
33 NXKey_t perthreadkey; /* if -1, no key obtained... */
34 NXMutex_t *lock;
35 } libdata_t;
36
37 int gLibId = -1;
38 void *gLibHandle = (void *) NULL;
39 rtag_t gAllocTag = (rtag_t) NULL;
40 NXMutex_t *gLibLock = (NXMutex_t *) NULL;
41
42 /* internal library function prototypes... */
43 int DisposeLibraryData ( void * );
44 void DisposeThreadData ( void * );
45 int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata );
46
47
_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)48 int _NonAppStart( void *NLMHandle,
49 void *errorScreen,
50 const char *cmdLine,
51 const char *loadDirPath,
52 size_t uninitializedDataLength,
53 void *NLMFileHandle,
54 int (*readRoutineP)( int conn,
55 void *fileHandle, size_t offset,
56 size_t nbytes,
57 size_t *bytesRead,
58 void *buffer ),
59 size_t customDataOffset,
60 size_t customDataSize,
61 int messageCount,
62 const char **messages )
63 {
64 NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
65
66 #ifndef __GNUC__
67 #pragma unused(cmdLine)
68 #pragma unused(loadDirPath)
69 #pragma unused(uninitializedDataLength)
70 #pragma unused(NLMFileHandle)
71 #pragma unused(readRoutineP)
72 #pragma unused(customDataOffset)
73 #pragma unused(customDataSize)
74 #pragma unused(messageCount)
75 #pragma unused(messages)
76 #endif
77
78 /*
79 ** Here we process our command line, post errors (to the error screen),
80 ** perform initializations and anything else we need to do before being able
81 ** to accept calls into us. If we succeed, we return non-zero and the NetWare
82 ** Loader will leave us up, otherwise we fail to load and get dumped.
83 */
84 gAllocTag = AllocateResourceTag(NLMHandle,
85 "<library-name> memory allocations", AllocSignature);
86
87 if (!gAllocTag) {
88 OutputToScreen(errorScreen, "Unable to allocate resource tag for "
89 "library memory allocations.\n");
90 return -1;
91 }
92
93 gLibId = register_library(DisposeLibraryData);
94
95 if (gLibId < -1) {
96 OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
97 return -1;
98 }
99
100 gLibHandle = NLMHandle;
101
102 gLibLock = NXMutexAlloc(0, 0, &liblock);
103
104 if (!gLibLock) {
105 OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
106 return -1;
107 }
108
109 return 0;
110 }
111
112 /*
113 ** Here we clean up any resources we allocated. Resource tags is a big part
114 ** of what we created, but NetWare doesn't ask us to free those.
115 */
_NonAppStop(void)116 void _NonAppStop( void )
117 {
118 (void) unregister_library(gLibId);
119 NXMutexFree(gLibLock);
120 }
121
122 /*
123 ** This function cannot be the first in the file for if the file is linked
124 ** first, then the check-unload function's offset will be nlmname.nlm+0
125 ** which is how to tell that there isn't one. When the check function is
126 ** first in the linked objects, it is ambiguous. For this reason, we will
127 ** put it inside this file after the stop function.
128 **
129 ** Here we check to see if it's alright to ourselves to be unloaded. If not,
130 ** we return a non-zero value. Right now, there isn't any reason not to allow
131 ** it.
132 */
_NonAppCheckUnload(void)133 int _NonAppCheckUnload( void )
134 {
135 return 0;
136 }
137
GetOrSetUpData(int id,libdata_t ** appData,libthreaddata_t ** threadData)138 int GetOrSetUpData(int id, libdata_t **appData, libthreaddata_t **threadData)
139 {
140 int err;
141 libdata_t *app_data;
142 libthreaddata_t *thread_data;
143 NXKey_t key;
144 NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
145
146 err = 0;
147 thread_data = (libthreaddata_t *) NULL;
148
149 /*
150 ** Attempt to get our data for the application calling us. This is where we
151 ** store whatever application-specific information we need to carry in support
152 ** of calling applications.
153 */
154 app_data = (libdata_t *) get_app_data(id);
155
156 if (!app_data) {
157 /*
158 ** This application hasn't called us before; set up application AND per-thread
159 ** data. Of course, just in case a thread from this same application is calling
160 ** us simultaneously, we better lock our application data-creation mutex. We
161 ** also need to recheck for data after we acquire the lock because WE might be
162 ** that other thread that was too late to create the data and the first thread
163 ** in will have created it.
164 */
165 NXLock(gLibLock);
166
167 if (!(app_data = (libdata_t *) get_app_data(id))) {
168 app_data = (libdata_t *) malloc(sizeof(libdata_t));
169
170 if (app_data) {
171 memset(app_data, 0, sizeof(libdata_t));
172
173 app_data->tenbytes = malloc(10);
174 app_data->lock = NXMutexAlloc(0, 0, &liblock);
175
176 if (!app_data->tenbytes || !app_data->lock) {
177 if (app_data->lock)
178 NXMutexFree(app_data->lock);
179
180 free(app_data);
181 app_data = (libdata_t *) NULL;
182 err = ENOMEM;
183 }
184
185 if (app_data) {
186 /*
187 ** Here we burn in the application data that we were trying to get by calling
188 ** get_app_data(). Next time we call the first function, we'll get this data
189 ** we're just now setting. We also go on here to establish the per-thread data
190 ** for the calling thread, something we'll have to do on each application
191 ** thread the first time it calls us.
192 */
193 err = set_app_data(gLibId, app_data);
194
195 if (err) {
196 free(app_data);
197 app_data = (libdata_t *) NULL;
198 err = ENOMEM;
199 }
200 else {
201 /* create key for thread-specific data... */
202 err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
203
204 if (err) /* (no more keys left?) */
205 key = -1;
206
207 app_data->perthreadkey = key;
208 }
209 }
210 }
211 }
212
213 NXUnlock(gLibLock);
214 }
215
216 if (app_data) {
217 key = app_data->perthreadkey;
218
219 if (key != -1 /* couldn't create a key? no thread data */
220 && !(err = NXKeyGetValue(key, (void **) &thread_data))
221 && !thread_data) {
222 /*
223 ** Allocate the per-thread data for the calling thread. Regardless of whether
224 ** there was already application data or not, this may be the first call by a
225 ** a new thread. The fact that we allocation 20 bytes on a pointer is not very
226 ** important, this just helps to demonstrate that we can have arbitrarily
227 ** complex per-thread data.
228 */
229 thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t));
230
231 if (thread_data) {
232 thread_data->_errno = 0;
233 thread_data->twentybytes = malloc(20);
234
235 if (!thread_data->twentybytes) {
236 free(thread_data);
237 thread_data = (libthreaddata_t *) NULL;
238 err = ENOMEM;
239 }
240
241 if ((err = NXKeySetValue(key, thread_data))) {
242 free(thread_data->twentybytes);
243 free(thread_data);
244 thread_data = (libthreaddata_t *) NULL;
245 }
246 }
247 }
248 }
249
250 if (appData)
251 *appData = app_data;
252
253 if (threadData)
254 *threadData = thread_data;
255
256 return err;
257 }
258
DisposeLibraryData(void * data)259 int DisposeLibraryData( void *data )
260 {
261 if (data) {
262 void *tenbytes = ((libdata_t *) data)->tenbytes;
263
264 if (tenbytes)
265 free(tenbytes);
266
267 free(data);
268 }
269
270 return 0;
271 }
272
DisposeThreadData(void * data)273 void DisposeThreadData( void *data )
274 {
275 if (data) {
276 void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
277
278 if (twentybytes)
279 free(twentybytes);
280
281 free(data);
282 }
283 }
284
285 #else /* __NOVELL_LIBC__ */
286 /* For native CLib-based NLM seems we can do a bit more simple. */
287 #include <nwthread.h>
288
main(void)289 int main ( void )
290 {
291 /* initialize any globals here... */
292
293 /* do this if any global initializing was done
294 SynchronizeStart();
295 */
296 ExitThread (TSR_THREAD, 0);
297 return 0;
298 }
299
300 #endif /* __NOVELL_LIBC__ */
301
302 #endif /* NETWARE */
303
304
305