1 |
/* |
2 |
openisis - an open implementation of the CDS/ISIS database |
3 |
Version 0.8.x (patchlevel see file Version) |
4 |
Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org |
5 |
|
6 |
This library is free software; you can redistribute it and/or |
7 |
modify it under the terms of the GNU Lesser General Public |
8 |
License as published by the Free Software Foundation; either |
9 |
version 2.1 of the License, or (at your option) any later version. |
10 |
|
11 |
This library is distributed in the hope that it will be useful, |
12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
Lesser General Public License for more details. |
15 |
|
16 |
You should have received a copy of the GNU Lesser General Public |
17 |
License along with this library; if not, write to the Free Software |
18 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
|
20 |
see README for more information |
21 |
EOH */ |
22 |
|
23 |
/* |
24 |
$Id: lses.c,v 1.18 2003/05/26 10:55:10 kripke Exp $ |
25 |
implementation of general db access functions. |
26 |
*/ |
27 |
|
28 |
#include <stdlib.h> |
29 |
#include <string.h> /* memset */ |
30 |
|
31 |
#ifdef _REENTRANT |
32 |
#ifdef WIN32 |
33 |
# define WIN32_LEAN_AND_MEAN |
34 |
# define NONAMELESSUNION |
35 |
# include <windows.h> |
36 |
/* they call it "thread local storage" */ |
37 |
# define pthread_key_t int |
38 |
# define pthread_key_create( pkey, func ) *(pkey) = TlsAlloc() |
39 |
# define pthread_setspecific( key, val ) TlsSetValue( key, val ) |
40 |
# define pthread_getspecific( key ) TlsGetValue( key ) |
41 |
#else |
42 |
# include <pthread.h> |
43 |
#endif |
44 |
#endif |
45 |
|
46 |
#include "lses.h" |
47 |
|
48 |
|
49 |
/* ************************************************************ |
50 |
private types |
51 |
*/ |
52 |
typedef struct { |
53 |
Ses h; |
54 |
/* int brk; */ |
55 |
} SesI; |
56 |
|
57 |
enum { |
58 |
LSES_MAX = 0x1000, |
59 |
LSES_MSK = 0x0fff |
60 |
}; |
61 |
|
62 |
/* ************************************************************ |
63 |
package data |
64 |
*/ |
65 |
|
66 |
/* ************************************************************ |
67 |
private data |
68 |
*/ |
69 |
static Ios stdio[3] = { |
70 |
LIO_STDINITIALIZER( "&0", LIO_IN ), |
71 |
LIO_STDINITIALIZER( "&1", LIO_OUT|1 ), |
72 |
LIO_STDINITIALIZER( "&2", LIO_OUT|2 ) |
73 |
}; |
74 |
static SesI cses = { /* the default session */ |
75 |
{ |
76 |
0, |
77 |
"", |
78 |
{ stdio, stdio+1, stdio+2 }, |
79 |
-1, |
80 |
0, 0, /* nxt, accnt */ |
81 |
{0},{0},{0}, /* times */ |
82 |
0,0,0,0 /* state */ |
83 |
} |
84 |
}; |
85 |
|
86 |
static SesI *tab[ LSES_MAX ] = { |
87 |
&cses |
88 |
}; |
89 |
static Ses *htab[ LSES_MAX ]; |
90 |
static int maxid; |
91 |
static const char oops[] = "out of memory\n"; |
92 |
|
93 |
#ifndef _REENTRANT |
94 |
Session ses = &cses.h; |
95 |
#else |
96 |
int openisis_threaded = 42; |
97 |
static pthread_key_t seskey; |
98 |
#endif |
99 |
|
100 |
/* ************************************************************ |
101 |
private functions |
102 |
*/ |
103 |
|
104 |
static void *memordie ( int size ) |
105 |
{ |
106 |
void *p = malloc( size ); |
107 |
if ( p ) |
108 |
return p; |
109 |
/* TODO: ask btree to release some cache */ |
110 |
lio_write( &lio_err, oops, sizeof(oops)-1 ); |
111 |
exit( 71/*EX_OSERR*/ ); /* exit handlers MUST NOT alloc memory */ |
112 |
return 0; |
113 |
} |
114 |
|
115 |
|
116 |
/* ************************************************************ |
117 |
package functions |
118 |
*/ |
119 |
|
120 |
void lses_init () /* called from openIsisInit */ |
121 |
{ |
122 |
#ifdef _REENTRANT |
123 |
pthread_key_create( &seskey, 0 ); /* TODO: use ses destr func */ |
124 |
pthread_setspecific( seskey, &cses.h ); |
125 |
#endif |
126 |
} /* lses_init */ |
127 |
|
128 |
|
129 |
void lses_fini () /* called from openIsisFini */ |
130 |
{ |
131 |
int i, s = LSES_MAX; |
132 |
/* lio_write( &lio_out, "fini time\n", 9 ); */ |
133 |
while ( s-- ) |
134 |
if ( tab[s] ) |
135 |
for ( i=0; i<3; i++ ) |
136 |
if ( tab[s]->h.io[i] ) |
137 |
LIO_CLOSE( tab[s]->h.io[i] ); |
138 |
} /* lses_fini */ |
139 |
|
140 |
|
141 |
int lses_open ( Session s, const char *name, int flags, SFunc *type ) |
142 |
{ |
143 |
int fd = 0; |
144 |
const char *p = name; |
145 |
lio_sfunc *func = type ? (lio_sfunc*)type : lio_stdio; |
146 |
|
147 |
/* check for i<> */ |
148 |
while ( '0' <= *p && *p <= '9' ) |
149 |
fd = 10*fd + *p++ - '0'; |
150 |
if ( '<' != *p && '>' != *p ) |
151 |
p = name; /* forget it */ |
152 |
else { |
153 |
if ( name == p && '>' == *p ) /* no fd given, > defaults to 1 */ |
154 |
fd = 1; |
155 |
flags |= '<' == *p ? LIO_RD : LIO_WR; |
156 |
p++; |
157 |
} |
158 |
if ( p == name ) { /* no fd given, find one */ |
159 |
for ( fd=0; s->io[fd]; ) |
160 |
if ( LSES_FILE_MAX == ++fd ) |
161 |
return -ERR_NOMEM; |
162 |
} else if ( s->io[fd] ) { /* close existing */ |
163 |
func( s->io[fd], LIO_SCLOSE ); |
164 |
/* don't kill the statics :) */ |
165 |
if ( s->io[fd] < stdio || s->io[fd] > stdio+2 ) |
166 |
mFree( s->io[fd] ); |
167 |
} |
168 |
s->io[fd] = (Ios*)mAlloc( func( 0, LIO_SSIZE ) ); |
169 |
if ( ! s->io[fd] ) |
170 |
return -ERR_NOMEM; |
171 |
s->io[fd]->func = func; |
172 |
s->io[fd]->name = mDup( p, -1 ); |
173 |
s->io[fd]->file = flags; |
174 |
return func( s->io[fd], LIO_SOPEN ); |
175 |
} /* lses_open */ |
176 |
|
177 |
|
178 |
|
179 |
/* ************************************************************ |
180 |
public functions |
181 |
*/ |
182 |
|
183 |
extern Ses *sGet () |
184 |
{ |
185 |
#ifdef _REENTRANT |
186 |
Ses *ses; |
187 |
if ( ! (ses = (Ses*)pthread_getspecific( seskey )) ) |
188 |
pthread_setspecific( seskey, ses = cSession( 0 ) ); |
189 |
#endif |
190 |
return ses; |
191 |
} |
192 |
|
193 |
extern void sSet ( Ses *s ) |
194 |
{ |
195 |
#ifndef _REENTRANT |
196 |
ses = s; |
197 |
#else |
198 |
pthread_setspecific( seskey, s ); |
199 |
#endif |
200 |
} |
201 |
|
202 |
|
203 |
Ses *cOpen ( Rec *args ) |
204 |
{ |
205 |
extern void linit(); |
206 |
|
207 |
linit(); |
208 |
if ( args ) { /* add args */ |
209 |
/* TODO: merge args */ |
210 |
cses.h.prop = rDup( args, -1, 0 ); |
211 |
} |
212 |
return &cses.h; |
213 |
} /* cOpen */ |
214 |
|
215 |
|
216 |
Ses *cSession ( Rec *args ) |
217 |
{ |
218 |
SesI *sesi = 0; |
219 |
Ses *s = 0; |
220 |
int id = 1; |
221 |
/** XXX unless we actually free sessions, |
222 |
we should start checking with maxid |
223 |
or check for expiry |
224 |
*/ |
225 |
while ( tab[id] ) |
226 |
if ( LSES_MAX == ++id ) |
227 |
return 0; |
228 |
if ( maxid < id ) |
229 |
maxid = id; |
230 |
sesi = tab[id] = (SesI*)malloc( sizeof(SesI) ); |
231 |
memset( sesi, 0, sizeof(SesI) ); |
232 |
s = &sesi->h; |
233 |
s->id = id; |
234 |
s->hash = -1; /* not hashed (hash is non-negative) */ |
235 |
s->prop = args ? rDup( args, -1, 0 ) : 0; |
236 |
/* check props */ |
237 |
/* open files */ |
238 |
lses_open( s, "2>&2", 0, lio_stdio ); |
239 |
return s; |
240 |
} /* cSession */ |
241 |
|
242 |
|
243 |
void *mAlloc ( int size ) |
244 |
{ |
245 |
void *p = memordie( size ); |
246 |
memset(p, 0, size); |
247 |
return p; |
248 |
} /* mAlloc */ |
249 |
|
250 |
|
251 |
void mFree ( void *mem ) |
252 |
{ |
253 |
if ( mem ) |
254 |
free( mem ); |
255 |
} /* mFree */ |
256 |
|
257 |
|
258 |
void *mDup ( const void *str, int sz ) |
259 |
{ |
260 |
void *m = memordie( 0<=sz ? sz : (sz = strlen( str ) + 1) ); |
261 |
memcpy( m, str, sz ); |
262 |
return m; |
263 |
} /* mDup */ |
264 |
|
265 |
|
266 |
int sOpen ( const char *name, int flags, SFunc *type ) |
267 |
{ |
268 |
SESDECL |
269 |
return lses_open( ses, name, flags, type ); |
270 |
} /* sOpen */ |
271 |
|
272 |
|
273 |
Ses *openIsisId2Session (int sid) { |
274 |
if (0 > sid || LSES_MAX <= sid || 0 == tab[sid]) { |
275 |
return (Ses*)0; |
276 |
} |
277 |
return &(tab[sid]->h); |
278 |
} /* openIsisId2Session */ |
279 |
|
280 |
|
281 |
int openIsisSession2Id (Ses *s) { |
282 |
if (0 == s) { |
283 |
return -1; |
284 |
} |
285 |
return s->id; |
286 |
} /* openIsisSession2Id */ |
287 |
|
288 |
|
289 |
Ses *cSesByName ( char *name, int nlen, Tm *now, Tm *expire ) |
290 |
{ |
291 |
char tbuf[20]; |
292 |
int h,i; |
293 |
Ses *s; |
294 |
if ( nlen < 0 ) |
295 |
nlen = strlen(name); |
296 |
if ( nlen > 63 ) |
297 |
nlen = 63; |
298 |
for ( i=nlen; i--; ) |
299 |
if ( !(0xe0 & name[i]) ) |
300 |
name[i] = '_'; |
301 |
h = lhash( name, nlen ); |
302 |
for ( s = htab[h & LSES_MSK]; s; s = s->nxt ) |
303 |
if ( h == s->hash |
304 |
&& !memcmp( name, s->name, nlen ) |
305 |
&& !s->name[nlen] |
306 |
) { /* match */ |
307 |
if ( !expire || s->atime.millis >= expire->millis ) |
308 |
goto gotit; /* valid */ |
309 |
if ( s->cur || s->que ) { |
310 |
log_msg( LOG_WARN, "expired session %d %s still busy!", |
311 |
s->id, s->name ); |
312 |
goto gotit; /* valid anyway */ |
313 |
} |
314 |
goto refresh; |
315 |
} |
316 |
/* didn't find by name */ |
317 |
if ( ! expire ) /* bad thing -- we're going to run out of sessions ... */ |
318 |
i = maxid+1; |
319 |
else /* check other expired */ |
320 |
for ( i=1; i<=maxid; i++ ) { |
321 |
s = &tab[i]->h; /* sind wir heute defensiv ... */ |
322 |
if ( s && s->atime.millis < expire->millis |
323 |
&& s->atime.millis && 0 <= s->hash /* else is none of our biz */ |
324 |
&& !s->cur && !s->que /* else is busy !? */ |
325 |
) |
326 |
break; |
327 |
} |
328 |
if ( i > maxid ) { |
329 |
s = cSession( 0 ); |
330 |
if ( ! s ) |
331 |
return 0; |
332 |
} else /* got one */ |
333 |
log_msg( LOG_INFO, "reusing session %d '%s' atime %s", |
334 |
s->id, s->name, s->atime.millis ? timeGtf(tbuf,&s->atime) : "-" ); |
335 |
if ( 0 <= s->hash ) { /* was hashed -- unlink */ |
336 |
Ses **spp = &htab[s->hash & LSES_MSK]; |
337 |
for ( ; *spp; spp = &(*spp)->nxt ) |
338 |
if ( s == *spp ) { |
339 |
*spp = s->nxt; |
340 |
break; |
341 |
} |
342 |
} |
343 |
memset( s->name, 0, sizeof(s->name) ); |
344 |
memcpy( s->name, name, nlen ); |
345 |
s->hash = h; |
346 |
s->nxt = htab[h & LSES_MSK]; |
347 |
htab[h & LSES_MSK] = s; |
348 |
refresh: |
349 |
s->ctime.millis = s->mtime.millis = now ? now->millis : 0; |
350 |
s->accnt = 0; |
351 |
if ( s->prop ) |
352 |
CLRREC( s->prop ); |
353 |
if ( s->res ) |
354 |
CLRREC( s->res ); |
355 |
gotit: |
356 |
s->atime.millis = now ? now->millis : 0; |
357 |
return s; |
358 |
} /* cSesByName */ |