1 /* -*- mode: c ; c-file-style: "canonware-c-style" -*-
2  ******************************************************************************
3  *
4  * Copyright (C) 1996-2005 Jason Evans <jasone@canonware.com>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice(s), this list of conditions and the following disclaimer
12  *    unmodified other than the allowable addition of one or more
13  *    copyright notices.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice(s), this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  ******************************************************************************
32  *
33  * Version: Onyx 5.1.2
34  *
35  ******************************************************************************/
36 
37 #ifdef CW_DBG
38 #define CW_NXO_THREAD_BUFFER_SIZE 8
39 #else
40 #define CW_NXO_THREAD_BUFFER_SIZE 256
41 #endif
42 
43 typedef struct cw_nxo_threadp_s cw_nxo_threadp_t;
44 typedef struct cw_nxoe_thread_s cw_nxoe_thread_t;
45 
46 typedef struct cw_nxoe_threadts_s cw_nxoe_threadts_t;
47 typedef enum
48 {
49     THREADTS_START,
50     THREADTS_COMMENT,
51     THREADTS_INTEGER,
52     THREADTS_INTEGER_RADIX,
53 #ifdef CW_REAL
54     THREADTS_REAL_FRAC,
55     THREADTS_REAL_EXP,
56 #endif
57     THREADTS_STRING,
58     THREADTS_STRING_NEWLINE_CONT,
59     THREADTS_STRING_PROT_CONT,
60     THREADTS_STRING_CRLF_CONT,
61     THREADTS_STRING_CTRL_CONT,
62     THREADTS_STRING_HEX_CONT,
63     THREADTS_STRING_HEX_FINISH,
64     THREADTS_NAME_START,
65     THREADTS_NAME
66 } cw_nxo_threadts_t;
67 
68 struct cw_nxo_threadp_s
69 {
70 #ifdef CW_DBG
71     uint32_t magic;
72 #endif
73 
74     /* Current origin/length, line number (counting starts at 1 by convention)
75      * and column number (counting starts at 0). */
76     const char *origin;
77     uint32_t olen;
78 
79     uint32_t line;
80     int32_t column;
81 };
82 
83 struct cw_nxoe_thread_s
84 {
85     cw_nxoe_t nxoe;
86 
87     /* nx this thread is part of. */
88     cw_nx_t *nx;
89 
90     /* Self, for the self operator, and as a convenience in various places
91      * internally. */
92     cw_nxo_t self;
93 
94 #ifdef CW_THREADS
95     /* Used by nxo_thread_thread(), nxo_thread_detach(), and
96      * nxo_thread_join(). */
97     cw_thd_t *thd;
98     cw_mtx_t lock;
99     cw_cnd_t done_cnd;
100     cw_cnd_t join_cnd;
101     bool done:1;
102     bool gone:1;
103     bool detached:1;
104     bool joined:1;
105 #endif
106 
107 #ifdef CW_THREADS
108     /* true  : New array, dict, file, and string objects are implicitly locked.
109      * false : No implicit locking for new objects. */
110     bool locking:1;
111 #endif
112 
113     /* Current maximum estack depth. */
114     cw_nxoi_t maxestack;
115 
116     /* If 1, optimize tail calls; if 0, do not optimize tail calls. */
117     uint32_t tailopt;
118 
119     /* Stacks. */
120 
121     /* Execution stack. */
122     cw_nxo_t estack;
123 
124     /* Execution index stack. */
125     cw_nxo_t istack;
126 
127     /* Operand stack. */
128     cw_nxo_t ostack;
129 
130     /* Dictionary stack. */
131     cw_nxo_t dstack;
132 
133 #ifdef CW_OOP
134     /* Context stack. */
135     cw_nxo_t cstack;
136 #endif
137 
138     /* Temp stack. */
139     cw_nxo_t tstack;
140 
141     /* Files. */
142     cw_nxo_t stdin_nxo;
143     cw_nxo_t stdout_nxo;
144     cw_nxo_t stderr_nxo;
145 
146     /* Argument passed by the escape operator to the trapped operator. */
147     cw_nxo_t trapped_arg;
148 
149 #ifdef CW_REGEX
150     /* Cached regular expression state used by the match operator.  This needs
151      * to be stored here since the cache is per-thread, and there is no other
152      * reasonable place to store the information that provides adequate
153      * performance.  Stuffing this in threaddict would impose a huge
154      * performance penalty due to dstack lookup overhead.
155      *
156      * The thread object initializes this structure, reports object
157      * references during GC reference iteration, and frees allocated memory.
158      * Otherwise, all operations on this structure are done by the regex class.
159      */
160     cw_nxo_regex_cache_t regex_cache;
161 #endif
162 
163     /* Tokenizer state.  If a token is broken across two or more input strings,
164      * data are copied to an internal buffer, and state machine state is
165      * preserved so that the buffered data need not be processed again. */
166 
167     /* Current scanner state. */
168     cw_nxo_threadts_t state;
169 
170     /* Every time a '{' token is encountered by the scanner, this value is
171      * incremented, and this value is decremented every time the scanner
172      * encounters a '}' token.  Execution of objects is deferred if this value
173      * is non-zero. */
174     uint32_t defer_count;
175 
176     /* Offset of first invalid character in tok_str. */
177     uint32_t index;
178 
179     /* Pointer to the token buffer.  As long as index is less than
180      * CW_NXO_THREAD_BUFFER_SIZE, tok_str actually points to buffer.  Otherwise,
181      * adequate space is allocated (using exponential doubling), and the
182      * contents of tok_buffer are copied to the allocated buffer.
183      *
184      * If a temporary buffer is allocated, it is discarded as soon as the token
185      * is handled.  That is, tok_buffer is used for every token until (if)
186      * tok_buffer overflows. */
187     char *tok_str;
188     uint32_t buffer_len; /* Only valid if buffer overflowed. */
189     char buffer[CW_NXO_THREAD_BUFFER_SIZE];
190 
191     union
192     {
193 	/* integer/real.  Which fields are valid (and whether the number is an
194 	 * integer or real) is implicit in the scanner state. */
195 	struct
196 	{
197 	    /* Mantissa. */
198 	    bool mant_neg:1; /* false: Positive. true: Negative. */
199 
200 	    /* Radix number base for mantissa (integers only). */
201 	    uint32_t radix_base:7; /* Radix (2-36).  Error detection requires
202 				       * space to store up to 99. */
203 
204 	    /* Whole part of mantissa (or radix integer). */
205 	    bool whole:1; /* false: No whole portion of mantissa.
206 				* true: Whole portion of mantissa. */
207 	    uint32_t whole_off; /* Offset to first digit of whole. */
208 	    uint32_t whole_len; /* Length of whole. */
209 
210 #ifdef CW_REAL
211 	    /* Fractional part of mantissa. */
212 	    bool frac:1; /* false: No fractional portion of mantissa.
213 			       * true: Fractional portion of mantissa. */
214 	    uint32_t frac_off; /* Offset to first digit of fractional. */
215 	    uint32_t frac_len; /* Length of fractional. */
216 
217 	    /* Exponent. */
218 	    bool exp:1; /* false: No exponent specified.
219 			 * true: Exponential notation. */
220 	    bool exp_sign:1; /* false: No sign.  true: Sign. */
221 	    bool exp_neg:1; /* false: Positive.  true: Negative. */
222 	    uint32_t exp_off; /* Offset to first digit of exponent. */
223 	    uint32_t exp_len; /* Length of exponent. */
224 #endif
225 	} n;
226 
227 	/* string. */
228 	struct
229 	{
230 	    uint32_t q_depth;
231 	    char hex_val;
232 	} s;
233 
234 	/* name. */
235 	struct
236 	{
237 	    /* The values of the first four actions must correspond to the
238 	     * values of the attributes in cw_nxoa_t, since the two enumerations
239 	     * are used interchangeably in nxoe_p_thread_name_accept(). */
240 	    enum
241 	    {
242 		ACTION_LITERAL = NXOA_LITERAL,
243 		ACTION_EXECUTE = NXOA_EXECUTABLE,
244 		ACTION_EVALUATE = NXOA_EVALUABLE,
245 #ifdef CW_OOP
246 		ACTION_CALL = NXOA_CALLABLE,
247 		ACTION_INVOKE = NXOA_INVOKABLE,
248 		ACTION_FETCH = NXOA_FETCHABLE,
249 #endif
250 		ACTION_IMMEDIATE
251 	    } action;
252 	} m;
253     } m;
254 };
255 
256 /* nxo_threadp. */
257 void
258 nxo_threadp_new(cw_nxo_threadp_t *a_threadp);
259 
260 void
261 nxo_threadp_delete(cw_nxo_threadp_t *a_threadp, cw_nxo_t *a_thread);
262 
263 void
264 nxo_threadp_origin_get(const cw_nxo_threadp_t *a_threadp,
265 		       const char **r_origin, uint32_t *r_olen);
266 
267 void
268 nxo_threadp_origin_set(cw_nxo_threadp_t *a_threadp,
269 		       const char *a_origin, uint32_t a_olen);
270 
271 void
272 nxo_threadp_position_get(const cw_nxo_threadp_t *a_threadp, uint32_t *r_line,
273 			 uint32_t *r_column);
274 
275 void
276 nxo_threadp_position_set(cw_nxo_threadp_t *a_threadp, uint32_t a_line,
277 			 uint32_t a_column);
278 
279 /* nxo_thread. */
280 void
281 nxo_thread_new(cw_nxo_t *a_nxo, cw_nx_t *a_nx);
282 
283 void
284 nxo_thread_start(cw_nxo_t *a_nxo);
285 
286 void
287 nxo_thread_exit(cw_nxo_t *a_nxo);
288 
289 #ifdef CW_THREADS
290 void
291 nxo_thread_thread(cw_nxo_t *a_nxo);
292 
293 void
294 nxo_thread_detach(cw_nxo_t *a_nxo);
295 
296 void
297 nxo_thread_join(cw_nxo_t *a_nxo);
298 #endif
299 
300 cw_nxo_threadts_t
301 nxo_thread_state(const cw_nxo_t *a_nxo);
302 
303 bool
304 nxo_thread_deferred(cw_nxo_t *a_nxo);
305 
306 void
307 nxo_thread_reset(cw_nxo_t *a_nxo);
308 
309 void
310 nxo_thread_loop(cw_nxo_t *a_nxo);
311 
312 void
313 nxo_thread_interpret(cw_nxo_t *a_nxo, cw_nxo_threadp_t *a_threadp, const
314 		     char *a_str, uint32_t a_len);
315 
316 void
317 nxo_thread_flush(cw_nxo_t *a_nxo, cw_nxo_threadp_t *a_threadp);
318 
319 void
320 nxo_thread_nerror(cw_nxo_t *a_nxo, cw_nxn_t a_nxn);
321 
322 void
323 nxo_thread_serror(cw_nxo_t *a_nxo, const char *a_str, uint32_t a_len);
324 
325 bool
326 nxo_thread_dstack_search(cw_nxo_t *a_nxo, cw_nxo_t *a_key, cw_nxo_t *r_value);
327 
328 #ifdef CW_OOP
329 bool
330 nxo_thread_class_hier_search(cw_nxo_t *a_nxo, cw_nxo_t *a_class,
331 			     cw_nxo_t *a_key, cw_nxo_t *r_value);
332 #endif
333 
334 #ifdef CW_THREADS
335 bool
336 nxo_thread_currentlocking(const cw_nxo_t *a_nxo);
337 
338 void
339 nxo_thread_setlocking(cw_nxo_t *a_nxo, bool a_locking);
340 #else
341 #define nxo_thread_currentlocking(a_nxo) false
342 #endif
343 
344 void
345 nxo_thread_maxestack_set(cw_nxo_t *a_nxo, cw_nxoi_t a_maxestack);
346 
347 void
348 nxo_thread_tailopt_set(cw_nxo_t *a_nxo, bool a_tailopt);
349 
350 void
351 nxo_thread_stdin_set(cw_nxo_t *a_nxo, cw_nxo_t *a_stdin);
352 
353 void
354 nxo_thread_stdout_set(cw_nxo_t *a_nxo, cw_nxo_t *a_stdout);
355 
356 void
357 nxo_thread_stderr_set(cw_nxo_t *a_nxo, cw_nxo_t *a_stderr);
358 
359 #ifndef CW_USE_INLINES
360 cw_nx_t *
361 nxo_thread_nx_get(cw_nxo_t *a_nxo);
362 
363 cw_nxoi_t
364 nxo_thread_maxestack_get(cw_nxo_t *a_nxo);
365 
366 bool
367 nxo_thread_tailopt_get(cw_nxo_t *a_nxo);
368 
369 cw_nxo_t *
370 nxo_thread_ostack_get(cw_nxo_t *a_nxo);
371 
372 #ifdef CW_OOP
373 cw_nxo_t *
374 nxo_thread_cstack_get(cw_nxo_t *a_nxo);
375 #endif
376 
377 cw_nxo_t *
378 nxo_thread_dstack_get(cw_nxo_t *a_nxo);
379 
380 cw_nxo_t *
381 nxo_thread_estack_get(cw_nxo_t *a_nxo);
382 
383 cw_nxo_t *
384 nxo_thread_istack_get(cw_nxo_t *a_nxo);
385 
386 cw_nxo_t *
387 nxo_thread_tstack_get(cw_nxo_t *a_nxo);
388 
389 cw_nxo_t *
390 nxo_thread_stdin_get(cw_nxo_t *a_nxo);
391 
392 cw_nxo_t *
393 nxo_thread_stdout_get(cw_nxo_t *a_nxo);
394 
395 cw_nxo_t *
396 nxo_thread_stderr_get(cw_nxo_t *a_nxo);
397 #endif
398 
399 #if (defined(CW_USE_INLINES) || defined(CW_NXO_THREAD_C_))
400 CW_INLINE cw_nx_t *
nxo_thread_nx_get(cw_nxo_t * a_nxo)401 nxo_thread_nx_get(cw_nxo_t *a_nxo)
402 {
403     cw_nxoe_thread_t *thread;
404 
405     cw_check_ptr(a_nxo);
406     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
407 
408     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
409     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
410     cw_assert(thread->nxoe.type == NXOT_THREAD);
411 
412     return thread->nx;
413 }
414 
415 CW_INLINE cw_nxoi_t
nxo_thread_maxestack_get(cw_nxo_t * a_nxo)416 nxo_thread_maxestack_get(cw_nxo_t *a_nxo)
417 {
418     cw_nxoe_thread_t *thread;
419 
420     cw_check_ptr(a_nxo);
421     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
422 
423     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
424     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
425     cw_assert(thread->nxoe.type == NXOT_THREAD);
426 
427     return thread->maxestack;
428 }
429 
430 CW_INLINE bool
nxo_thread_tailopt_get(cw_nxo_t * a_nxo)431 nxo_thread_tailopt_get(cw_nxo_t *a_nxo)
432 {
433     bool retval;
434     cw_nxoe_thread_t *thread;
435 
436     cw_check_ptr(a_nxo);
437     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
438 
439     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
440     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
441     cw_assert(thread->nxoe.type == NXOT_THREAD);
442 
443     if (thread->tailopt)
444     {
445 	retval = true;
446     }
447     else
448     {
449 	retval = false;
450     }
451 
452     return retval;
453 }
454 
455 CW_INLINE cw_nxo_t *
nxo_thread_ostack_get(cw_nxo_t * a_nxo)456 nxo_thread_ostack_get(cw_nxo_t *a_nxo)
457 {
458     cw_nxoe_thread_t *thread;
459 
460     cw_check_ptr(a_nxo);
461     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
462 
463     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
464     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
465     cw_assert(thread->nxoe.type == NXOT_THREAD);
466 
467     return &thread->ostack;
468 }
469 
470 #ifdef CW_OOP
471 CW_INLINE cw_nxo_t *
nxo_thread_cstack_get(cw_nxo_t * a_nxo)472 nxo_thread_cstack_get(cw_nxo_t *a_nxo)
473 {
474     cw_nxoe_thread_t *thread;
475 
476     cw_check_ptr(a_nxo);
477     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
478 
479     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
480     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
481     cw_assert(thread->nxoe.type == NXOT_THREAD);
482 
483     return &thread->cstack;
484 }
485 #endif
486 
487 CW_INLINE cw_nxo_t *
nxo_thread_dstack_get(cw_nxo_t * a_nxo)488 nxo_thread_dstack_get(cw_nxo_t *a_nxo)
489 {
490     cw_nxoe_thread_t *thread;
491 
492     cw_check_ptr(a_nxo);
493     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
494 
495     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
496     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
497     cw_assert(thread->nxoe.type == NXOT_THREAD);
498 
499     return &thread->dstack;
500 }
501 
502 CW_INLINE cw_nxo_t *
nxo_thread_estack_get(cw_nxo_t * a_nxo)503 nxo_thread_estack_get(cw_nxo_t *a_nxo)
504 {
505     cw_nxoe_thread_t *thread;
506 
507     cw_check_ptr(a_nxo);
508     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
509 
510     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
511     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
512     cw_assert(thread->nxoe.type == NXOT_THREAD);
513 
514     return &thread->estack;
515 }
516 
517 CW_INLINE cw_nxo_t *
nxo_thread_istack_get(cw_nxo_t * a_nxo)518 nxo_thread_istack_get(cw_nxo_t *a_nxo)
519 {
520     cw_nxoe_thread_t *thread;
521 
522     cw_check_ptr(a_nxo);
523     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
524 
525     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
526     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
527     cw_assert(thread->nxoe.type == NXOT_THREAD);
528 
529     return &thread->istack;
530 }
531 
532 CW_INLINE cw_nxo_t *
nxo_thread_tstack_get(cw_nxo_t * a_nxo)533 nxo_thread_tstack_get(cw_nxo_t *a_nxo)
534 {
535     cw_nxoe_thread_t *thread;
536 
537     cw_check_ptr(a_nxo);
538     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
539 
540     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
541     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
542     cw_assert(thread->nxoe.type == NXOT_THREAD);
543 
544     return &thread->tstack;
545 }
546 
547 CW_INLINE cw_nxo_t *
nxo_thread_stdin_get(cw_nxo_t * a_nxo)548 nxo_thread_stdin_get(cw_nxo_t *a_nxo)
549 {
550     cw_nxoe_thread_t *thread;
551 
552     cw_check_ptr(a_nxo);
553     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
554 
555     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
556     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
557     cw_assert(thread->nxoe.type == NXOT_THREAD);
558 
559     return &thread->stdin_nxo;
560 }
561 
562 CW_INLINE cw_nxo_t *
nxo_thread_stdout_get(cw_nxo_t * a_nxo)563 nxo_thread_stdout_get(cw_nxo_t *a_nxo)
564 {
565     cw_nxoe_thread_t *thread;
566 
567     cw_check_ptr(a_nxo);
568     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
569 
570     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
571     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
572     cw_assert(thread->nxoe.type == NXOT_THREAD);
573 
574     return &thread->stdout_nxo;
575 }
576 
577 CW_INLINE cw_nxo_t *
nxo_thread_stderr_get(cw_nxo_t * a_nxo)578 nxo_thread_stderr_get(cw_nxo_t *a_nxo)
579 {
580     cw_nxoe_thread_t *thread;
581 
582     cw_check_ptr(a_nxo);
583     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
584 
585     thread = (cw_nxoe_thread_t *) a_nxo->o.nxoe;
586     cw_dassert(thread->nxoe.magic == CW_NXOE_MAGIC);
587     cw_assert(thread->nxoe.type == NXOT_THREAD);
588 
589     return &thread->stderr_nxo;
590 }
591 #endif /* (defined(CW_USE_INLINES) || defined(CW_NXO_THREAD_C_)) */
592