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