1 |
dpavlin |
237 |
/* |
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 */ |