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