1 /* Copyright(C) 2004-2007 Brazil
2 
3   This library is free software; you can redistribute it and/or
4   modify it under the terms of the GNU Lesser General Public
5   License as published by the Free Software Foundation; either
6   version 2.1 of the License, or (at your option) any later version.
7 
8   This library is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   Lesser General Public License for more details.
12 
13   You should have received a copy of the GNU Lesser General Public
14   License along with this library; if not, write to the Free Software
15   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17 #ifndef SEN_CTX_H
18 #define SEN_CTX_H
19 
20 #ifdef HAVE_ERRNO_H
21 #include <errno.h>
22 #endif /* HAVE_ERRNO_H */
23 
24 #ifndef SEN_COM_H
25 #include "com.h"
26 #endif /* SEN_COM_H */
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 /**** error handling ****/
33 
34 #define SEN_OP_T0LVL 0
35 #define SEN_OP_ERR0  1
36 
37 enum {
38   SEN_EMERG = sen_log_emerg,
39   SEN_ALERT = sen_log_alert,
40   SEN_CRIT = sen_log_crit,
41   SEN_ERROR = sen_log_error,
42   SEN_WARN = sen_log_warning,
43   SEN_OK = sen_log_notice
44 };
45 
46 #define ERRCLR(ctx) do {\
47   if (ctx) {\
48     ((sen_ctx *)ctx)->errlvl = SEN_OK;\
49     ((sen_ctx *)ctx)->rc = sen_success;\
50   }\
51   sen_gctx.errlvl = SEN_OK;\
52   sen_gctx.rc = sen_success;\
53 } while (0)
54 
55 #define ERRSET(ctx,lvl,r,...) do {\
56   ((sen_ctx *)ctx)->errlvl = (lvl);\
57   ((sen_ctx *)ctx)->rc = (r);\
58   ((sen_ctx *)ctx)->errfile = __FILE__;\
59   ((sen_ctx *)ctx)->errline = __LINE__;\
60   ((sen_ctx *)ctx)->errfunc = __FUNCTION__;\
61   ((sen_ctx *)ctx)->cur = ((sen_ctx *)ctx)->str_end;\
62   ((sen_ctx *)ctx)->op = SEN_OP_ERR0;\
63   SEN_LOG(lvl, __VA_ARGS__);\
64   sen_ctx_log((sen_ctx *)ctx, __VA_ARGS__);\
65 } while (0)
66 
67 #define ERRP(ctx,lvl) (((ctx) && ((sen_ctx *)(ctx))->errlvl <= (lvl)) || (sen_gctx.errlvl <= (lvl)))
68 
69 #define QLERR(...) do {\
70   ERRSET(ctx, SEN_WARN, sen_invalid_argument, __VA_ARGS__);\
71   return F;\
72 } while (0)
73 
74 #define QLASSERT(expr) do {\
75   if (!(expr)) { QLERR("syntax error"); }\
76 } while (0)
77 
78 #define ERR(rc,...) ERRSET(ctx, SEN_ERROR, (rc),  __VA_ARGS__)
79 #define MERR(...) ERRSET(ctx, SEN_ALERT, sen_memory_exhausted,  __VA_ARGS__)
80 #define SERR(str) ERR(sen_other_error, "syscall error '%s' (%s)", str, strerror(errno))
81 
82 #define GERR(rc,...) ERRSET(&sen_gctx, SEN_ERROR, (rc),  __VA_ARGS__)
83 #define GMERR(...) ERRSET(&sen_gctx, SEN_ALERT, sen_memory_exhausted,  __VA_ARGS__)
84 #define GSERR(str) GERR(sen_other_error, "syscall error '%s' (%s)", str, strerror(errno))
85 
86 #ifdef USE_FAIL_MALLOC
87 #define SEN_MALLOC(s) sen_fail_malloc(ctx,s,__FILE__,__LINE__,__FUNCTION__)
88 #define SEN_CALLOC(s) sen_fail_calloc(ctx,s,__FILE__,__LINE__,__FUNCTION__)
89 #define SEN_REALLOC(p,s) sen_fail_realloc(ctx,p,s,__FILE__,__LINE__,__FUNCTION__)
90 #define SEN_STRDUP(s) sen_fail_strdup(ctx,s,__FILE__,__LINE__,__FUNCTION__)
91 #define SEN_GMALLOC(s) sen_fail_malloc(&sen_gctx,s,__FILE__,__LINE__,__FUNCTION__)
92 #define SEN_GCALLOC(s) sen_fail_calloc(&sen_gctx,s,__FILE__,__LINE__,__FUNCTION__)
93 #define SEN_GREALLOC(p,s) sen_fail_realloc(&sen_gctx,p,s,__FILE__,__LINE__,__FUNCTION__)
94 #define SEN_GSTRDUP(s) sen_fail_strdup(&sen_gctx,s,__FILE__,__LINE__,__FUNTION__)
95 #else /* USE_FAIL_MALLOC */
96 #define SEN_MALLOC(s) sen_malloc(ctx,s,__FILE__,__LINE__)
97 #define SEN_CALLOC(s) sen_calloc(ctx,s,__FILE__,__LINE__)
98 #define SEN_REALLOC(p,s) sen_realloc(ctx,p,s,__FILE__,__LINE__)
99 #define SEN_STRDUP(s) sen_strdup(ctx,s,__FILE__,__LINE__)
100 #define SEN_GMALLOC(s) sen_malloc(&sen_gctx,s,__FILE__,__LINE__)
101 #define SEN_GCALLOC(s) sen_calloc(&sen_gctx,s,__FILE__,__LINE__)
102 #define SEN_GREALLOC(p,s) sen_realloc(&sen_gctx,p,s,__FILE__,__LINE__)
103 #define SEN_GSTRDUP(s) sen_strdup(&sen_gctx,s,__FILE__,__LINE__)
104 #endif /* USE_FAIL_MALLOC */
105 #define SEN_FREE(p) sen_free(ctx,p,__FILE__,__LINE__)
106 #define SEN_MALLOCN(t,n) ((t *)(SEN_MALLOC(sizeof(t) * (n))))
107 #define SEN_GFREE(p) sen_free(&sen_gctx,p,__FILE__,__LINE__)
108 #define SEN_GMALLOCN(t,n) ((t *)(SEN_GMALLOC(sizeof(t) * (n))))
109 
110 #ifdef DEBUG
111 #define SEN_ASSERT(s) sen_assert((s),__FILE__,__LINE__,__FUNCTION__)
112 #else
113 #define SEN_ASSERT(s)
114 #endif
115 
116 #ifdef USE_FAIL_MALLOC
117 int fail_malloc_check(size_t size, const char *file, int line, const char *func);
118 void *sen_fail_malloc(sen_ctx *ctx, size_t size, const char* file, int line, const char *func);
119 void *sen_fail_calloc(sen_ctx *ctx, size_t size, const char* file, int line, const char *func);
120 void *sen_fail_realloc(sen_ctx *ctx, void *ptr, size_t size, const char* file, int line, const char *func);
121 char *sen_fail_strdup(sen_ctx *ctx, const char *s, const char* file, int line, const char *func);
122 #endif /* USE_FAIL_MALLOC */
123 void *sen_malloc(sen_ctx *ctx, size_t size, const char* file, int line);
124 void *sen_calloc(sen_ctx *ctx, size_t size, const char* file, int line);
125 void *sen_realloc(sen_ctx *ctx, void *ptr, size_t size, const char* file, int line);
126 char *sen_strdup(sen_ctx *ctx, const char *s, const char* file, int line);
127 void sen_free(sen_ctx *ctx, void *ptr, const char* file, int line);
128 
129 void sen_assert(int cond, const char* file, int line, const char* func);
130 
131 void sen_index_expire(void);
132 
133 /**** sen_obj ****/
134 
135 typedef struct {
136   int32_t tv_sec;
137   int32_t tv_usec;
138 } sen_timeval;
139 
140 typedef struct _sen_obj sen_obj;
141 typedef struct _sen_ql_co sen_ql_co;
142 typedef sen_obj *sen_ql_native_func(sen_ctx *, sen_obj *, sen_ql_co *);
143 
144 struct _sen_obj {
145   uint8_t type;
146   uint8_t nrefs;
147   uint16_t flags;
148   sen_id class;
149   union {
150     struct {
151       sen_id self;
152       sen_ql_native_func *func;
153     } o;
154     struct {
155       void *value;
156       sen_ql_native_func *func;
157     } p;
158     struct {
159       char *value;
160       uint32_t size;
161     } b;
162     struct {
163       sen_obj *car;
164       sen_obj *cdr;
165     } l;
166     struct {
167       int64_t i;
168     } i;
169     struct {
170       double d;
171     } d;
172     struct {
173       int8_t op;
174       int8_t mode;
175       int16_t weight;
176       int32_t option;
177     } op;
178     sen_timeval tv;
179   } u;
180 };
181 
182 struct _sen_ql_co {
183   uint16_t mode;
184   uint16_t last;
185   sen_ql_native_func *func;
186   void *data;
187 };
188 
189 /**** sen_array ****/
190 
191 typedef struct _sen_array sen_array;
192 
193 enum {
194   SEN_ARRAY_CLEAR = 1,
195   SEN_ARRAY_THREADSAFE = 2
196 };
197 
198 // #define SEN_ARRAY_W 2
199 #define SEN_ARRAY_W 0
200 #define SEN_ARRAY_R(i) (1<<((i)<<SEN_ARRAY_W))
201 #define SEN_ARRAY_S (SEN_ARRAY_R(1)-1)
202 #define SEN_ARRAY_N (32>>SEN_ARRAY_W)
203 
204 struct _sen_array {
205   sen_ctx *ctx;
206   sen_id max;
207   uint16_t element_size;
208   uint16_t flags;
209   sen_mutex lock;
210   void *elements[SEN_ARRAY_N];
211 };
212 
213 #define SEN_ARRAY_EACH(a,head,tail,key,val,block) do {\
214   int _ei;\
215   const sen_id h = (head);\
216   const sen_id t = (tail);\
217   for (_ei = 0, (key) = (h); _ei < SEN_ARRAY_N && (key) <= (t); _ei++) {\
218     int _ej = SEN_ARRAY_S * SEN_ARRAY_R(_ei);\
219     if (((val) = (a)->elements[_ei])) {\
220       for (; _ej-- && (key) <= (t); (key)++, (val) = (void *)((byte *)(val) + (a)->element_size)) block\
221     } else {\
222       (key) += _ej;\
223     }\
224   }\
225 } while (0)
226 
227 #define SEN_ARRAY_AT(a,id,e) do {\
228   sen_id id_ = (id);\
229   byte **e_;\
230   size_t o_;\
231   {\
232     int l_, i_;\
233     if (!id_) { e = NULL; break; }\
234     SEN_BIT_SCAN_REV(id_, l_);\
235     i_ = l_ >> SEN_ARRAY_W;\
236     o_ = SEN_ARRAY_R(i_);\
237     e_ = (byte **)&(a)->elements[i_];\
238   }\
239   if (!*e_) {\
240     sen_ctx *ctx = (a)->ctx;\
241     if ((a)->flags & SEN_ARRAY_THREADSAFE) { MUTEX_LOCK((a)->lock); }\
242     if (!*e_) {\
243       if ((a)->flags & SEN_ARRAY_CLEAR) {\
244         *e_ = SEN_CALLOC(SEN_ARRAY_S * o_ * (a)->element_size);\
245       } else {\
246         *e_ = SEN_MALLOC(SEN_ARRAY_S * o_ * (a)->element_size);\
247       }\
248     }\
249     if ((a)->flags & SEN_ARRAY_THREADSAFE) { MUTEX_UNLOCK((a)->lock); }\
250     if (!*e_) { e = NULL; break; }\
251   }\
252   if (id_ > (a)->max) { (a)->max = id_; }\
253   (e) = (void *)(*e_ + (id_ - o_) * (a)->element_size);\
254 } while (0)
255 
256 #define SEN_ARRAY_NEXT(a,e) SEN_ARRAY_AT((a), (a)->max + 1, e)
257 
258 void sen_array_init(sen_array *a, sen_ctx *ctx, uint16_t element_size, uint16_t flags);
259 void sen_array_fin(sen_array *a);
260 void *sen_array_at(sen_array *a, sen_id id);
261 sen_id sen_array_id(sen_array *a, void *p);
262 
263 /**** sen_ctx ****/
264 
265 #ifndef SEN_STORE_H
266 #include "store.h"
267 #endif /* SEN_STORE_H */
268 
269 #define SEN_CTX_MSGSIZE 128
270 
271 // #define USE_SET_AS_OBJECTS
272 
273 struct _sen_ctx {
274   sen_rc rc;
275   uint8_t errlvl;
276   const char *errfile;
277   int errline;
278   const char *errfunc;
279   char errbuf[SEN_CTX_MSGSIZE];
280 
281   uint32_t ncells;
282   uint32_t seqno;
283   uint32_t lseqno;
284   uint32_t nbinds;
285   uint32_t nunbinds;
286   uint8_t feed_mode;
287   uint8_t stat;
288 
289   uint8_t batchmode;
290   uint8_t gc_verbose;
291 
292   sen_encoding encoding;
293 
294   int tok;
295   char *cur;
296   char *str_end;
297 
298   sen_obj **pht;       /* tail of placeholders */
299 
300   sen_obj arg;         /* wait_data container (for coroutine) */
301   sen_db *db;
302   uint32_t n_entries;
303 #ifdef USE_SET_AS_OBJECTS
304   sen_set *objects;    /* object table */
305 #else /* USE_SET_AS_OBJECTS */
306   sen_array objects;   /* object table */
307   sen_obj *freelist;   /* object free list */
308 #endif /* USE_SET_AS_OBJECTS */
309   sen_set *symbols;    /* symbol table */
310   sen_obj *phs;        /* list of placeholders */
311   sen_ql_co co;        /* coroutine info */
312 
313   sen_obj *args;       /* register for arguments of function */
314   sen_obj *envir;      /* stack register for current environment */
315   sen_obj *code;       /* register for current code */
316   sen_obj *dump;       /* stack register for next evaluation */
317   sen_obj *value;      /* evaluated value */
318   sen_obj *global_env; /* global variables */
319 
320   uint8_t op;
321 
322   char *inbuf;
323   sen_rbuf outbuf;
324   sen_rbuf subbuf;
325   unsigned int bufcur;
326 
327   void (*output)(sen_ctx *, int, void *);
328 
329   sen_com_sqtp *com;
330   unsigned int com_status;
331   unsigned int com_info;
332 
333   void *currec;        /* current recinfo (for slotexp) */
334   sen_obj curobj;      /* current record container (for slotexp) */
335 
336   union {
337     void *ptr;
338     int fd;
339     uint32_t u32;
340     uint64_t u64;
341   } data;
342 };
343 
344 extern sen_ctx sen_gctx;
345 
346 sen_obj *sen_get(const char *key);
347 sen_obj *sen_at(const char *key);
348 sen_rc sen_del(const char *key);
349 
350 #ifndef SEN_TIMEVAL_STR_SIZE
351 #define SEN_TIMEVAL_STR_SIZE 0x100
352 #endif /* SEN_TIMEVAL_STR_SIZE */
353 #ifndef SEN_TIMEVAL_STR_FORMAT
354 #define SEN_TIMEVAL_STR_FORMAT "%04d-%02d-%02d %02d:%02d:%02d.%06d"
355 #endif /* SEN_TIMEVAL_STR_FORMAT */
356 
357 sen_rc sen_timeval_now(sen_timeval *tv);
358 sen_rc sen_timeval2str(sen_timeval *tv, char *buf);
359 sen_rc sen_str2timeval(const char *str, uint32_t str_len, sen_timeval *tv);
360 
361 void sen_ctx_log(sen_ctx *ctx, char *fmt, ...);
362 
363 /**** receive handler ****/
364 
365 void sen_ctx_recv_handler_set(sen_ctx *c, void (*func)(sen_ctx *, int, void *),
366                               void *func_arg);
367 
368 void sen_ctx_concat_func(sen_ctx *ctx, int flags, void *dummy);
369 void sen_ctx_stream_out_func(sen_ctx *c, int flags, void *stream);
370 
371 #ifdef __cplusplus
372 }
373 #endif
374 
375 #endif /* SEN_CTX_H */
376