Qore Programming Language  0.9.16
qore_thread_intern.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  qore_thread_intern.h
4 
5  POSIX thread library for Qore
6 
7  Qore Programming Language
8 
9  Copyright (C) 2003 - 2020 Qore Technologies, s.r.o.
10 
11  Permission is hereby granted, free of charge, to any person obtaining a
12  copy of this software and associated documentation files (the "Software"),
13  to deal in the Software without restriction, including without limitation
14  the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  and/or sell copies of the Software, and to permit persons to whom the
16  Software is furnished to do so, subject to the following conditions:
17 
18  The above copyright notice and this permission notice shall be included in
19  all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  DEALINGS IN THE SOFTWARE.
28 
29  Note that the Qore library is released under a choice of three open-source
30  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
31  information.
32 */
33 
34 #ifndef _QORE_QORE_THREAD_INTERN_H
35 #define _QORE_QORE_THREAD_INTERN_H
36 
37 #include <vector>
38 #include <set>
39 #include <map>
40 
41 #ifndef QORE_THREAD_STACK_SIZE
42 #define QORE_THREAD_STACK_SIZE 1024*512
43 #endif
44 
45 // the values here are subject to change and come from purely empirical testing
46 #ifndef QORE_STACK_GUARD
47 #ifdef CPU_X86_64
48 // for some reason we need 32K of stack guard on x86_64
49 #define QORE_STACK_GUARD (1024 * 32)
50 #else
51 
52 #ifdef SPARC
53 // also we need at least 22K of stack guard on sparc for background threads for some reason
54 #define QORE_STACK_GUARD (1024 * 22)
55 #else
56 
57 #if defined(HPUX) && !defined(__ia64) && !defined(__LP64__)
58 // need 10KB on HPUX on 32-bit pa-risc
59 #define QORE_STACK_GUARD (1024 * 10)
60 #else
61 
62 // "generic" value (tested on OSX i386 and ppc and Linux i386)
63 #define QORE_STACK_GUARD (1024 * 8)
64 #endif // HPUX
65 
66 #endif // SPARC
67 #endif // CPU_X86_64
68 #endif // QORE_STACK_GUARD
69 
70 class Operator;
71 class Context;
72 class CVNode;
73 class CallNode;
74 class CallStack;
75 class LocalVar;
76 class LocalVarValue;
77 class ClosureParseEnvironment;
78 class QoreClosureBase;
79 hashdecl ClosureVarValue;
80 class VLock;
81 class ConstantEntry;
82 class qore_ns_private;
83 class qore_root_ns_private;
84 class qore_class_private;
85 class AbstractQoreFunctionVariant;
86 class AbstractQoreZoneInfo;
87 class ThreadProgramData;
88 hashdecl ThreadLocalProgramData;
89 class QoreAbstractModule;
90 class QoreRWLock;
91 
92 DLLLOCAL extern Operator* OP_BACKGROUND;
93 
94 class VNode;
95 class AbstractQoreZoneInfo;
96 class ThreadData;
97 
98 hashdecl ModuleContextNamespaceCommit {
99  qore_ns_private* parent;
100  qore_ns_private* nns;
101 
102  DLLLOCAL ModuleContextNamespaceCommit(qore_ns_private* n_parent, qore_ns_private* n_nns) : parent(n_parent), nns(n_nns) {
103  }
104 };
105 
106 typedef std::vector<ModuleContextNamespaceCommit> mcnl_t;
107 
108 class ModuleContextNamespaceList : public mcnl_t {
109 private:
110  // not implemented
111  DLLLOCAL ModuleContextNamespaceList(const ModuleContextNamespaceList&);
112 
113 public:
114  DLLLOCAL ModuleContextNamespaceList() {
115  }
116 
117  DLLLOCAL ~ModuleContextNamespaceList() {
118  assert(empty());
119  }
120 
121  DLLLOCAL void clear();
122 };
123 
124 hashdecl ModuleContextFunctionCommit {
125  qore_ns_private* parent;
126  const char* name;
127  AbstractQoreFunctionVariant* v;
128 
129  DLLLOCAL ModuleContextFunctionCommit(qore_ns_private* n_parent, const char* n_name, AbstractQoreFunctionVariant* n_v) : parent(n_parent), name(n_name), v(n_v) {
130  }
131 };
132 
133 typedef std::vector<ModuleContextFunctionCommit> mcfl_t;
134 
135 class ModuleContextFunctionList : public mcfl_t {
136 private:
137  // not implemented
138  DLLLOCAL ModuleContextFunctionList(const ModuleContextFunctionList&);
139 
140 public:
141  DLLLOCAL ModuleContextFunctionList() {
142  }
143 
144  DLLLOCAL ~ModuleContextFunctionList() {
145  assert(empty());
146  }
147 
148  DLLLOCAL void clear();
149 };
150 
151 class QoreModuleContext {
152 public:
153  ModuleContextNamespaceList mcnl;
154  ModuleContextFunctionList mcfl;
155 
156  DLLLOCAL QoreModuleContext(const char* n, qore_root_ns_private* n_rns, ExceptionSink& xs) : name(n), rns(n_rns), xsink(xs) {
157  }
158 
159  DLLLOCAL ~QoreModuleContext() {
160  assert(!err);
161  }
162 
163  DLLLOCAL void error(const char* fmt, ...);
164 
165  DLLLOCAL bool hasError() const {
166  return xsink;
167  }
168 
169  DLLLOCAL void commit();
170 
171  DLLLOCAL void rollback() {
172  mcnl.clear();
173  mcfl.clear();
174  }
175 
176  DLLLOCAL qore_root_ns_private* getRootNS() const {
177  return rns;
178  }
179 
180  DLLLOCAL const char* getName() const {
181  return name;
182  }
183 
184 protected:
185  const char* name;
186  qore_root_ns_private* rns;
187  QoreStringNode* err = nullptr;
188  ExceptionSink& xsink;
189 };
190 
191 class QoreModuleDefContext {
192 public:
193  typedef std::set<std::string> strset_t;
194  typedef std::map<std::string, std::string> strmap_t;
195 
196  QoreValue init_c, // the initialization closure
197  del_c; // the destructor closure
198 
199  const QoreProgramLocation* init_loc,
200  * del_loc;
201 
202  DLLLOCAL QoreModuleDefContext() {
203  }
204 
205  DLLLOCAL ~QoreModuleDefContext() {
206  init_c.discard(nullptr);
207  del_c.discard(nullptr);
208  }
209 
210  // set of valid tags
211  static strset_t vset;
212 
213  // set of tag definitions
214  strmap_t vmap;
215 
216  DLLLOCAL void set(const QoreProgramLocation* loc, const char* key, QoreValue val);
217 
218  DLLLOCAL const char* get(const char* str) const {
219  strmap_t::const_iterator i = vmap.find(str);
220  return i == vmap.end() || i->second.empty() ? nullptr : i->second.c_str();
221  }
222 
223  DLLLOCAL void parseInit();
224 
225  DLLLOCAL bool hasInit() const {
226  return init_c ? true : false;
227  }
228 
229  DLLLOCAL int init(QoreProgram& pgm, ExceptionSink& xsink);
230 
231  DLLLOCAL AbstractQoreNode* takeDel();
232 
233 protected:
234  DLLLOCAL void initClosure(const QoreProgramLocation* loc, QoreValue& c, const char* n);
235 };
236 
237 DLLLOCAL QoreValue do_op_background(const QoreValue left, ExceptionSink* xsink);
238 
239 // returns 0 if the last mark has been cleared, -1 if there are more marks to check
240 DLLLOCAL int purge_thread_resources_to_mark(ExceptionSink* xsink);
241 DLLLOCAL void purge_thread_resources(ExceptionSink* xsink);
242 DLLLOCAL void purge_pgm_thread_resources(const QoreProgram* pgm, ExceptionSink* xsink);
243 DLLLOCAL void mark_thread_resources();
244 DLLLOCAL void beginParsing(const char* file, void* ps = NULL, const char* src = nullptr, int offset = 0);
245 DLLLOCAL void* endParsing();
246 DLLLOCAL Context* get_context_stack();
247 DLLLOCAL void update_context_stack(Context* cstack);
248 
249 DLLLOCAL const QoreStackLocation* get_runtime_stack_location();
250 DLLLOCAL const QoreStackLocation* update_get_runtime_stack_location(QoreStackLocation* stack_loc,
251  const AbstractStatement*& current_stmt, QoreProgram*& current_pgm);
252 DLLLOCAL const QoreStackLocation* update_get_runtime_stack_builtin_location(QoreStackLocation* stack_loc,
253  const AbstractStatement*& current_stmt, QoreProgram*& current_pgm, const QoreProgramLocation*& old_runtime_loc);
254 DLLLOCAL void update_runtime_stack_location(const QoreStackLocation* stack_loc);
255 DLLLOCAL void update_runtime_stack_location(const QoreStackLocation* stack_loc, const QoreProgramLocation* runtime_loc);
256 
257 DLLLOCAL const QoreProgramLocation* get_runtime_location();
258 DLLLOCAL void update_get_runtime_statement_location(const AbstractStatement* stmt,
259  const QoreProgramLocation* loc, const AbstractStatement*& old_stmt, const QoreProgramLocation*& old_loc);
260 DLLLOCAL void update_runtime_statement_location(const AbstractStatement* stmt, const QoreProgramLocation* loc);
261 
262 DLLLOCAL void set_parse_file_info(QoreProgramLocation& loc);
263 DLLLOCAL const char* get_parse_code();
264 
265 DLLLOCAL const AbstractStatement* get_runtime_statement();
266 
267 DLLLOCAL const QoreTypeInfo* parse_set_implicit_arg_type_info(const QoreTypeInfo* ti);
268 DLLLOCAL const QoreTypeInfo* parse_get_implicit_arg_type_info();
269 
270 DLLLOCAL int64 parse_get_parse_options();
271 DLLLOCAL int64 runtime_get_parse_options();
272 
273 DLLLOCAL bool parse_check_parse_option(int64 o);
274 DLLLOCAL bool runtime_check_parse_option(int64 o);
275 
276 DLLLOCAL RootQoreNamespace* getRootNS();
277 DLLLOCAL void updateCVarStack(CVNode* ncvs);
278 DLLLOCAL CVNode* getCVarStack();
279 DLLLOCAL void updateVStack(VNode* nvs);
280 DLLLOCAL VNode* getVStack();
281 
282 //DLLLOCAL void setParseClass(QoreClass* c);
283 DLLLOCAL QoreClass* parse_get_class();
284 DLLLOCAL qore_class_private* parse_get_class_priv();
285 DLLLOCAL void thread_set_class_and_ns(const qore_class_private* new_cls, qore_ns_private* new_ns, const qore_class_private*& old_cls, qore_ns_private*& old_ns);
286 DLLLOCAL void thread_set_class_and_ns(const qore_class_private* new_cls, qore_ns_private* new_ns);
287 DLLLOCAL void thread_set_ns(qore_ns_private* new_ns, qore_ns_private*& old_ns);
288 DLLLOCAL void thread_set_ns(qore_ns_private* new_ns);
289 DLLLOCAL qore_ns_private* parse_get_ns();
290 
291 DLLLOCAL void substituteObjectIfEqual(QoreObject* o);
292 DLLLOCAL QoreObject* substituteObject(QoreObject* o);
293 DLLLOCAL QoreException* catchSwapException(QoreException* e);
294 DLLLOCAL QoreException* catchGetException();
295 DLLLOCAL VLock* getVLock();
296 DLLLOCAL void end_signal_thread(ExceptionSink* xsink);
297 DLLLOCAL void delete_thread_local_data();
298 DLLLOCAL void parse_cond_push(bool mark = false);
299 DLLLOCAL bool parse_cond_else();
300 DLLLOCAL bool parse_cond_pop(const QoreProgramLocation* loc);
301 DLLLOCAL bool parse_cond_test(const QoreProgramLocation* loc);
302 DLLLOCAL void push_parse_options();
303 DLLLOCAL void parse_try_module_inc();
304 DLLLOCAL bool parse_try_module_dec(const QoreProgramLocation* loc);
305 DLLLOCAL unsigned parse_try_module_get();
306 DLLLOCAL void parse_try_module_set(unsigned c);
307 
308 DLLLOCAL void parse_push_name(const char* name);
309 DLLLOCAL std::string parse_pop_name();
310 
311 DLLLOCAL void set_module_context(QoreModuleContext* qmc);
312 DLLLOCAL QoreModuleContext* get_module_context();
313 DLLLOCAL QoreModuleDefContext* set_module_def_context(QoreModuleDefContext* qmd);
314 DLLLOCAL QoreModuleDefContext* get_module_def_context();
315 DLLLOCAL void parse_set_module_def_context_name(const char* name);
316 DLLLOCAL const char* set_user_module_context_name(const char* n);
317 DLLLOCAL const char* get_user_module_context_name();
318 DLLLOCAL const char* get_module_context_name();
319 
320 DLLLOCAL void parse_set_try_reexport(bool tr);
321 DLLLOCAL bool parse_get_try_reexport();
322 
323 DLLLOCAL void set_thread_tz(const AbstractQoreZoneInfo* tz);
324 DLLLOCAL const AbstractQoreZoneInfo* get_thread_tz(bool& set);
325 DLLLOCAL void clear_thread_tz();
326 
327 DLLLOCAL ThreadProgramData* get_thread_program_data();
328 DLLLOCAL ThreadLocalProgramData* get_thread_local_program_data();
329 
330 DLLLOCAL int thread_ref_set(const lvalue_ref* r);
331 DLLLOCAL void thread_ref_remove(const lvalue_ref* r);
332 
333 // pushes a new argv reference counter
334 DLLLOCAL void new_argv_ref();
335 
336 // increments the parse argv reference counter
337 DLLLOCAL void inc_argv_ref();
338 
339 // pushes an "ignore numeric reference" context
340 DLLLOCAL void push_ignore_numeric_argv_ref();
341 
342 // pops an "ignore numeric reference" context
343 DLLLOCAL void pop_ignore_numeric_argv_ref();
344 
345 // increments the parse argv reference counter for numeric references (ex: $1)
346 DLLLOCAL void inc_numeric_argv_ref();
347 
348 // gets the parse argv reference counter and pops the context
349 DLLLOCAL int get_pop_argv_ref();
350 
351 // clears the argv reference stack
352 DLLLOCAL void clear_argv_ref();
353 
354 DLLLOCAL int set_constant(ConstantEntry* ce);
355 DLLLOCAL void remove_constant(ConstantEntry* ce);
356 
357 DLLLOCAL QoreAbstractModule* set_reexport(QoreAbstractModule* m, bool current_reexport, bool& old_reexport);
358 DLLLOCAL void set_reexport(QoreAbstractModule* m, bool reexport);
359 
360 DLLLOCAL void parseSetCodeInfo(const char* parse_code, const QoreTypeInfo* returnTypeInfo, const char*& old_code, const QoreTypeInfo*& old_returnTypeInfo);
361 DLLLOCAL void parseRestoreCodeInfo(const char* parse_code, const QoreTypeInfo* returnTypeInfo);
362 // sets the new type and returns the old
363 DLLLOCAL const QoreTypeInfo* saveReturnTypeInfo(const QoreTypeInfo* returnTypeInfo);
364 DLLLOCAL const QoreTypeInfo* getReturnTypeInfo();
365 
366 DLLLOCAL const QoreTypeInfo* parse_get_return_type_info();
367 
368 DLLLOCAL QoreProgram* get_set_program_call_context(QoreProgram* new_pgm);
369 DLLLOCAL void set_program_call_context(QoreProgram* new_pgm);
370 
371 // issue #3242: make sure we can temporarily set any current lvar stack to nullptr when parsing out of order
372 class LVarStackBreakHelper {
373 public:
374  DLLLOCAL LVarStackBreakHelper();
375  DLLLOCAL ~LVarStackBreakHelper();
376 
377 private:
378  VNode* vnode;
379 };
380 
381 class ProgramCallContextHelper {
382 public:
383  DLLLOCAL ProgramCallContextHelper(QoreProgram* new_pgm);
384  DLLLOCAL ~ProgramCallContextHelper();
385 
386 private:
387  QoreProgram* pgm;
388 };
389 
390 class ModuleReExportHelper {
391 protected:
392  QoreAbstractModule* m;
393  bool reexport;
394 
395 public:
396  DLLLOCAL ModuleReExportHelper(QoreAbstractModule* mi, bool reexp);
397  DLLLOCAL ~ModuleReExportHelper();
398 };
399 
400 class QoreParseCountContextHelper {
401 protected:
402  unsigned count;
403 
404 public:
405  DLLLOCAL QoreParseCountContextHelper() : count(parse_try_module_get()) {
406  parse_try_module_set(0);
407  }
408 
409  DLLLOCAL ~QoreParseCountContextHelper() {
410  parse_try_module_set(count);
411  }
412 };
413 
414 class QoreProgramStackLocationHelper {
415 public:
416  DLLLOCAL QoreProgramStackLocationHelper(QoreStackLocation* stack_loc, const AbstractStatement*& current_stmt,
417  QoreProgram*& current_pgm) :
418  stack_loc(update_get_runtime_stack_location(stack_loc, current_stmt, current_pgm)) {
419  }
420 
421  DLLLOCAL ~QoreProgramStackLocationHelper() {
422  update_runtime_stack_location(stack_loc);
423  }
424 
425 protected:
426  const QoreStackLocation* stack_loc;
427 };
428 
429 class QoreInternalCallStackLocationHelperBase : public QoreStackLocation, public QoreProgramStackLocationHelper {
430 public:
431  DLLLOCAL QoreInternalCallStackLocationHelperBase() : QoreProgramStackLocationHelper(this, stmt, pgm) {
432  }
433 
434  DLLLOCAL virtual QoreProgram* getProgram() const {
435  return pgm;
436  }
437 
438  DLLLOCAL virtual const AbstractStatement* getStatement() const {
439  return stmt;
440  }
441 
442 protected:
443  const AbstractStatement* stmt;
444  QoreProgram* pgm;
445 };
446 
447 class QoreInternalCallStackLocationHelper : public QoreInternalCallStackLocationHelperBase {
448 public:
449  DLLLOCAL QoreInternalCallStackLocationHelper(const QoreProgramLocation& loc, const std::string& call,
450  qore_call_t call_type) : loc(loc), call(call), call_type(call_type) {
451  }
452 
454  DLLLOCAL virtual const QoreProgramLocation& getLocation() const {
455  return loc;
456  }
457 
459  DLLLOCAL virtual const std::string& getCallName() const {
460  return call;
461  }
462 
463  DLLLOCAL virtual qore_call_t getCallType() const {
464  return call_type;
465  }
466 
467 protected:
468  const QoreProgramLocation& loc;
469  const std::string call;
470  qore_call_t call_type;
471 };
472 
473 class QoreProgramLocationHelper {
474 public:
475  DLLLOCAL QoreProgramLocationHelper(const QoreProgramLocation* n_loc, const AbstractStatement* n_stat = nullptr) {
476  update_get_runtime_statement_location(n_stat, n_loc, statement, loc);
477  }
478 
479  DLLLOCAL ~QoreProgramLocationHelper() {
480  update_runtime_statement_location(statement, loc);
481  }
482 
483 protected:
484  const QoreProgramLocation* loc;
485  const AbstractStatement* statement;
486 };
487 
488 class QoreProgramOptionalLocationHelper {
489 public:
490  DLLLOCAL QoreProgramOptionalLocationHelper(const QoreProgramLocation* n_loc, const AbstractStatement* n_stat = nullptr) : restore((bool)n_loc) {
491  if (n_loc) {
492  update_get_runtime_statement_location(n_stat, n_loc, statement, loc);
493  }
494  }
495 
496  DLLLOCAL ~QoreProgramOptionalLocationHelper() {
497  if (restore) {
498  update_runtime_statement_location(statement, loc);
499  }
500  }
501 
502 protected:
503  const QoreProgramLocation* loc;
504  const AbstractStatement* statement;
505  bool restore;
506 };
507 
508 // allows for the parse lock for the current program to be acquired by binary modules
509 class CurrentProgramRuntimeParseContextHelper {
510 public:
511  // acquires the parse lock; if already acquired by another thread, then this call blocks until the lock can be acquired
512  DLLEXPORT CurrentProgramRuntimeParseContextHelper();
513  // releases the parse lock for the current program
514  DLLEXPORT ~CurrentProgramRuntimeParseContextHelper();
515 
516 private:
517  // not implemented
518  CurrentProgramRuntimeParseContextHelper(const CurrentProgramRuntimeParseContextHelper&) = delete;
519  void* operator new(size_t) = delete;
520 };
521 
522 // allows for implicit argument types to be set at parse time
523 class ParseImplicitArgTypeHelper {
524 public:
525  DLLLOCAL ParseImplicitArgTypeHelper(const QoreTypeInfo* ti) : ati(parse_set_implicit_arg_type_info(ti)) {
526  }
527 
528  DLLLOCAL ~ParseImplicitArgTypeHelper() {
529  parse_set_implicit_arg_type_info(ati);
530  }
531 
532 private:
533  const QoreTypeInfo* ati;
534 };
535 
536 // acquires a TID and thread entry, returns -1 if not successful
537 DLLLOCAL int get_thread_entry();
538 // acquires TID 0 and sets up the signal thread entry, always returns 0
539 DLLLOCAL int get_signal_thread_entry();
540 DLLLOCAL void deregister_signal_thread();
541 DLLLOCAL void register_thread(int tid, pthread_t ptid, QoreProgram* pgm, bool foreign = false);
542 DLLLOCAL void deregister_thread(int tid);
543 DLLLOCAL void delete_signal_thread();
544 
545 // returns 1 if data structure is already on stack, 0 if not (=OK)
546 DLLLOCAL int thread_push_container(const AbstractQoreNode* n);
547 DLLLOCAL void thread_pop_container(const AbstractQoreNode* n);
548 
549 // called when a StatementBlock has "on block exit" blocks
550 DLLLOCAL void pushBlock(block_list_t::iterator i);
551 // called when a StatementBlock has "on block exit" blocks
552 DLLLOCAL block_list_t::iterator popBlock();
553 // called by each "on_block_exit" statement to activate it's code for the block exit
554 DLLLOCAL void advanceOnBlockExit();
555 
556 DLLLOCAL LocalVarValue* thread_instantiate_lvar();
557 DLLLOCAL void thread_uninstantiate_lvar(ExceptionSink* xsink);
558 DLLLOCAL void thread_uninstantiate_self();
559 
560 DLLLOCAL void thread_set_closure_parse_env(ClosureParseEnvironment* cenv);
561 DLLLOCAL ClosureParseEnvironment* thread_get_closure_parse_env();
562 
563 DLLLOCAL ClosureVarValue* thread_instantiate_closure_var(const char* id, const QoreTypeInfo* typeInfo, QoreValue& nval, bool assign);
564 DLLLOCAL void thread_instantiate_closure_var(ClosureVarValue* cvar);
565 DLLLOCAL void thread_uninstantiate_closure_var(ExceptionSink* xsink);
566 DLLLOCAL ClosureVarValue* thread_find_closure_var(const char* id);
567 
568 DLLLOCAL ClosureVarValue* thread_get_runtime_closure_var(const LocalVar* id);
569 DLLLOCAL const QoreClosureBase* thread_set_runtime_closure_env(const QoreClosureBase* current);
570 
571 typedef std::vector<ClosureVarValue*> cvv_vec_t;
572 DLLLOCAL cvv_vec_t* thread_get_all_closure_vars();
573 
574 DLLLOCAL void thread_push_frame_boundary();
575 DLLLOCAL void thread_pop_frame_boundary();
576 
577 DLLLOCAL QoreHashNode* thread_get_local_vars(int frame, ExceptionSink* xsink);
578 // returns 0 = OK, 1 = no such variable, -1 exception setting variable
579 DLLLOCAL int thread_set_local_var_value(int frame, const char* name, const QoreValue& val, ExceptionSink* xsink);
580 // returns 0 = OK, 1 = no such variable, -1 exception setting variable
581 DLLLOCAL int thread_set_closure_var_value(int frame, const char* name, const QoreValue& val, ExceptionSink* xsink);
582 
583 DLLLOCAL int get_implicit_element();
584 DLLLOCAL int save_implicit_element(int n_element);
585 
586 DLLLOCAL VNode* update_get_vstack(VNode* vn);
587 DLLLOCAL void save_global_vnode(VNode* vn);
588 DLLLOCAL VNode* get_global_vnode();
589 
590 class QoreContainerHelper {
591  const AbstractQoreNode* n;
592  bool err;
593 
594 public:
595  DLLLOCAL QoreContainerHelper(const AbstractQoreNode* n_n) {
596  // FIXME! need to have an AbstactQoreNode::isContainer() function!
597  qore_type_t t = n_n ? n_n->getType() : NT_NOTHING;
598  if ((t == NT_LIST || t == NT_HASH || t == NT_OBJECT || t >= QORE_NUM_TYPES)) {
599  if (!thread_push_container(n_n)) {
600  n = n_n;
601  err = false;
602  }
603  else {
604  n = nullptr;
605  err = true;
606  }
607  }
608  else {
609  n = nullptr;
610  err = false;
611  }
612  }
613  DLLLOCAL ~QoreContainerHelper() {
614  if (n)
615  thread_pop_container(n);
616  }
617  DLLLOCAL operator bool () const {
618  return !err;
619  }
620 };
621 
622 DLLLOCAL const QoreListNode* thread_get_implicit_args();
623 
624 DLLLOCAL LocalVarValue* thread_find_lvar(const char* id);
625 
626 // to get the current runtime object
627 DLLLOCAL QoreObject* runtime_get_stack_object();
628 // to get the current runtime class
629 DLLLOCAL const qore_class_private* runtime_get_class();
630 DLLLOCAL void runtime_get_object_and_class(QoreObject*& obj, const qore_class_private*& qc);
631 // for methods that behave differently when called within the method itself (methodGate(), memberGate(), etc)
632 DLLLOCAL bool runtime_in_object_method(const char* name, const QoreObject* o);
633 
634 class CodeContextHelperBase {
635 private:
636  const char* old_code;
637  QoreObject* old_obj;
638  const qore_class_private* old_class;
639  QoreProgram* old_call_program_context;
640  bool do_ref,
641  do_program_context;
642 
643  ExceptionSink* xsink;
644 
645 public:
646  DLLLOCAL CodeContextHelperBase(const char* code, QoreObject* obj, const qore_class_private* c, ExceptionSink* xsink, bool ref_obj = true);
647  DLLLOCAL ~CodeContextHelperBase();
648 };
649 
650 class ObjectSubstitutionHelper {
651 private:
652  QoreObject* old_obj;
653  const qore_class_private* old_class;
654 
655 public:
656  DLLLOCAL ObjectSubstitutionHelper(QoreObject* obj, const qore_class_private* c);
657  DLLLOCAL ~ObjectSubstitutionHelper();
658 };
659 
660 class OptionalClassObjSubstitutionHelper {
661 public:
662  DLLLOCAL OptionalClassObjSubstitutionHelper(const qore_class_private* qc);
663  DLLLOCAL ~OptionalClassObjSubstitutionHelper();
664 
665 private:
666  QoreObject* old_obj;
667  const qore_class_private* old_class;
668  bool subst;
669 };
670 
671 class OptionalClassOnlySubstitutionHelper {
672 public:
673  DLLLOCAL OptionalClassOnlySubstitutionHelper(const qore_class_private* qc);
674  DLLLOCAL ~OptionalClassOnlySubstitutionHelper();
675 
676 private:
677  const qore_class_private* old_class;
678  bool subst;
679 };
680 
681 class OptionalObjectOnlySubstitutionHelper {
682 public:
683  DLLLOCAL OptionalObjectOnlySubstitutionHelper(QoreObject* obj);
684  DLLLOCAL ~OptionalObjectOnlySubstitutionHelper();
685 
686 private:
687  bool subst;
688  QoreObject* old_obj;
689 };
690 
691 class ThreadSafeLocalVarRuntimeEnvironmentHelper {
692 private:
693  const QoreClosureBase* prev;
694 
695 public:
696  DLLLOCAL ThreadSafeLocalVarRuntimeEnvironmentHelper(const QoreClosureBase* current);
697  DLLLOCAL ~ThreadSafeLocalVarRuntimeEnvironmentHelper();
698 };
699 
700 typedef std::map<const LocalVar*, ClosureVarValue*> cvar_map_t;
701 typedef std::set<ClosureVarValue*> cvv_set_t;
702 
703 class ThreadSafeLocalVarRuntimeEnvironment {
704 private:
705  cvar_map_t cmap;
706  cvv_set_t cvvset;
707 
708 public:
709  DLLLOCAL ThreadSafeLocalVarRuntimeEnvironment(const lvar_set_t* vlist);
710  DLLLOCAL ~ThreadSafeLocalVarRuntimeEnvironment();
711  DLLLOCAL ClosureVarValue* find(const LocalVar* id) const;
712  DLLLOCAL bool hasVar(ClosureVarValue* cvv) const;
713  DLLLOCAL void del(ExceptionSink* xsink);
714 
715  DLLLOCAL bool empty() {
716  return cmap.empty();
717  }
718 
719  DLLLOCAL const cvar_map_t& getMap() const {
720  return cmap;
721  }
722 };
723 
724 hashdecl ThreadLocalProgramData;
725 
726 class QoreProgramBlockParseOptionHelper {
727 public:
728  DLLLOCAL QoreProgramBlockParseOptionHelper(int64 n_po);
729  DLLLOCAL ~QoreProgramBlockParseOptionHelper();
730 
731 protected:
732  int64 po;
733 };
734 
735 class ProgramThreadCountContextHelper {
736 public:
737  DLLLOCAL ProgramThreadCountContextHelper(ExceptionSink* xsink, QoreProgram* pgm, bool runtime);
738  DLLLOCAL ~ProgramThreadCountContextHelper();
739  static ThreadLocalProgramData* getContextFrame(int& frame, ExceptionSink* xsink);
740  bool isFirstThreadLocalProgramData(const ThreadLocalProgramData* tlpd) const;
741 
742 protected:
743  QoreProgram* old_pgm = nullptr;
744  ThreadLocalProgramData* old_tlpd = nullptr;
745  ProgramThreadCountContextHelper* old_ctx = nullptr;
746  // frame count of tlpd when context is started
747  int save_frameCount = 0;
748  int old_frameCount;
749  bool restore = false;
750  bool init_tlpd = false;
751 };
752 
753 class ProgramRuntimeParseContextHelper {
754 protected:
755  QoreProgram* old_pgm;
756  bool restore;
757 
758 public:
759  DLLLOCAL ProgramRuntimeParseContextHelper(ExceptionSink* xsink, QoreProgram* pgm);
760  DLLLOCAL ~ProgramRuntimeParseContextHelper();
761 };
762 
763 // ensures the program is locked for parsing and that thread-local data is available for execution at parse commit time
764 class ProgramRuntimeParseCommitContextHelper {
765 protected:
766  QoreProgram* old_pgm;
767  ThreadLocalProgramData* old_tlpd;
768  bool restore;
769 
770 public:
771  DLLLOCAL ProgramRuntimeParseCommitContextHelper(ExceptionSink* xsink, QoreProgram* pgm);
772  DLLLOCAL ~ProgramRuntimeParseCommitContextHelper();
773 };
774 
775 class ProgramRuntimeParseAccessHelper {
776 protected:
777  QoreProgram* old_pgm;
778  bool restore;
779 
780 public:
781  DLLLOCAL ProgramRuntimeParseAccessHelper(ExceptionSink* xsink, QoreProgram* pgm);
782  DLLLOCAL ~ProgramRuntimeParseAccessHelper();
783 };
784 
785 class RuntimeReferenceHelperBase {
786 protected:
787  const lvalue_ref* ref;
788  ProgramThreadCountContextHelper pch;
789  ObjectSubstitutionHelper osh;
790  bool valid = true;
791 
792 public:
793  DLLLOCAL RuntimeReferenceHelperBase(const lvalue_ref& r, ExceptionSink* n_xsink)
794  : ref(&r), pch(n_xsink, r.pgm, true), osh(r.self, r.cls) {
795  //printd(5, "RuntimeReferenceHelperBase::RuntimeReferenceHelperBase() this: %p vexp: %p %s %d\n", this, r.vexp, get_type_name(r.vexp), get_node_type(r.vexp));
796  if (thread_ref_set(&r)) {
797  ref = nullptr;
798  n_xsink->raiseException("CIRCULAR-REFERENCE-ERROR", "a circular lvalue reference was detected");
799  valid = false;
800  }
801  }
802 
803  DLLLOCAL ~RuntimeReferenceHelperBase() {
804  if (ref)
805  thread_ref_remove(ref);
806  }
807 
808  DLLLOCAL operator bool() const {
809  return valid;
810  }
811 };
812 
813 class RuntimeReferenceHelper : public RuntimeReferenceHelperBase {
814 public:
815  DLLLOCAL RuntimeReferenceHelper(const ReferenceNode& r, ExceptionSink* n_xsink) : RuntimeReferenceHelperBase(*lvalue_ref::get(&r), n_xsink) {
816  }
817 
818  DLLLOCAL RuntimeReferenceHelper(const lvalue_ref& r, ExceptionSink* n_xsink) : RuntimeReferenceHelperBase(r, n_xsink) {
819  }
820 };
821 
822 class ArgvContextHelper {
823 private:
824  QoreListNode* old_argv;
825  ExceptionSink* xsink;
826 
827 public:
828  DLLLOCAL ArgvContextHelper(QoreListNode* argv, ExceptionSink* n_xsink);
829  // calls deref(xsink) on list in destructor
830  DLLLOCAL ~ArgvContextHelper();
831 };
832 
833 class SingleArgvContextHelper {
834 private:
835  QoreListNode* old_argv;
836  ExceptionSink* xsink;
837 
838 public:
839  // any reference in val will be overtaken by the SingleArgvContextHelper object
840  DLLLOCAL SingleArgvContextHelper(QoreValue val, ExceptionSink* n_xsink);
841  // calls deref(xsink) on list in destructor
842  DLLLOCAL ~SingleArgvContextHelper();
843 };
844 
845 class ImplicitElementHelper {
846 private:
847  int element;
848 
849 public:
850  DLLLOCAL ImplicitElementHelper(int n_element) : element(save_implicit_element(n_element)) {
851  }
852  DLLLOCAL ~ImplicitElementHelper() {
853  save_implicit_element(element);
854  }
855 };
856 
857 class CodeContextHelper : public CodeContextHelperBase {
858 public:
859  DLLLOCAL CodeContextHelper(ExceptionSink* xs, int t, const char* c, QoreObject* obj = nullptr, const qore_class_private* cls = nullptr, bool ref_obj = true) :
860  CodeContextHelperBase(c, obj, cls, xs, ref_obj) {
861  }
862 };
863 
864 DLLLOCAL void init_qore_threads();
865 DLLLOCAL QoreNamespace* get_thread_ns(QoreNamespace& qorens);
866 DLLLOCAL void delete_qore_threads();
867 DLLLOCAL QoreListNode* get_thread_list();
868 DLLLOCAL QoreHashNode* getAllCallStacks();
869 DLLLOCAL QoreListNode* qore_get_thread_call_stack();
870 
871 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) || (defined(QORE_HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE))
872 #define QORE_HAVE_GET_STACK_SIZE
873 #endif
874 
875 #if defined(QORE_HAVE_PTHREAD_SETNAME_NP_1) || defined(QORE_HAVE_PTHREAD_SETNAME_NP_2) || defined(QORE_HAVE_PTHREAD_SETNAME_NP_3) || defined(QORE_HAVE_PTHREAD_SET_NAME_NP)
876 #if defined(HAVE_PTHREAD_GET_NAME_NP) || defined(HAVE_PTHREAD_GETNAME_NP)
877 #define QORE_HAVE_THREAD_NAME
878 #endif
879 #endif
880 
881 class QorePThreadAttr {
882 private:
883  pthread_attr_t attr;
884 
885 public:
886  DLLLOCAL QorePThreadAttr() {
887  pthread_attr_init(&attr);
888  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
889  }
890 
891  DLLLOCAL ~QorePThreadAttr() {
892  //printd(2, "calling pthread_attr_destroy(%p)\n", &attr);
893  pthread_attr_destroy(&attr);
894  //printd(2, "returned from pthread_attr_destroy(%p)\n", &attr);
895  }
896 
897 #ifdef HAVE_PTHREAD_ATTR_GETSTACK
898  DLLLOCAL void getstack(void*& ptr, size_t& ssize) {
899  pthread_attr_getstack(&attr, &ptr, &ssize);
900  }
901 #endif
902 
903  DLLLOCAL size_t getstacksize() const {
904  size_t ssize;
905  pthread_attr_getstacksize(&attr, &ssize);
906  return ssize;
907  }
908 
909  DLLLOCAL int setstacksize(size_t ssize) {
910  return pthread_attr_setstacksize(&attr, ssize);
911  }
912 
913  DLLLOCAL pthread_attr_t* get_ptr() {
914  return &attr;
915  }
916 
917 #ifdef QORE_HAVE_GET_STACK_SIZE
918  DLLLOCAL static size_t getCurrentThreadStackSize() {
919 #ifdef HAVE_PTHREAD_GET_STACKSIZE_NP
920  return pthread_get_stacksize_np(pthread_self());
921 #else
922  pthread_attr_t attr;
923  if (pthread_getattr_np(pthread_self(), &attr)) {
924  return 0;
925  }
926  ON_BLOCK_EXIT(pthread_attr_destroy, &attr);
927  size_t size = 0;
928  if (pthread_attr_getstacksize(&attr, &size)) {
929  return 0;
930  }
931  return size;
932 #endif
933  }
934 #endif
935 };
936 
937 DLLLOCAL extern QorePThreadAttr ta_default;
938 
939 #ifdef QORE_MANAGE_STACK
940 DLLLOCAL int check_stack(ExceptionSink* xsink);
941 #endif
942 
943 class ParseCodeInfoHelper {
944 private:
945  const char* parse_code;
946  const QoreTypeInfo* returnTypeInfo;
947 
948 public:
949  DLLLOCAL ParseCodeInfoHelper(const char* n_parse_code, const QoreTypeInfo* n_returnTypeInfo) {
950  parseSetCodeInfo(n_parse_code, n_returnTypeInfo, parse_code, returnTypeInfo);
951  }
952 
953  DLLLOCAL ~ParseCodeInfoHelper() {
954  parseRestoreCodeInfo(parse_code, returnTypeInfo);
955  }
956 };
957 
958 class NamespaceParseContextHelper {
959 private:
960  qore_ns_private* ns;
961  bool restore;
962 
963 public:
964  DLLLOCAL NamespaceParseContextHelper(qore_ns_private* n_ns) {
965  thread_set_ns(n_ns, ns);
966  restore = (ns != n_ns);
967  }
968 
969  DLLLOCAL ~NamespaceParseContextHelper() {
970  if (restore) {
971  thread_set_ns(ns);
972  }
973  }
974 };
975 
976 class OptionalNamespaceParseContextHelper {
977 private:
978  qore_ns_private* ns;
979  bool restore;
980 
981 public:
982  DLLLOCAL OptionalNamespaceParseContextHelper(qore_ns_private* n_ns) {
983  if (n_ns) {
984  thread_set_ns(n_ns, ns);
985  restore = (ns != n_ns);
986  } else {
987  restore = false;
988  }
989  }
990 
991  DLLLOCAL ~OptionalNamespaceParseContextHelper() {
992  if (restore) {
993  thread_set_ns(ns);
994  }
995  }
996 };
997 
998 class QoreParseClassHelper {
999 protected:
1000  const qore_class_private* cls;
1001  qore_ns_private* ns;
1002  bool restore;
1003 
1004 public:
1005  DLLLOCAL QoreParseClassHelper(QoreClass* new_cls, qore_ns_private* new_ns = nullptr);
1006 
1007  DLLLOCAL ~QoreParseClassHelper();
1008 };
1009 
1010 class ThreadData;
1011 
1012 class ThreadProgramData : public QoreReferenceCounter {
1013 private:
1014  // for the set of QoreProgram objects we have local variables in
1015  typedef std::set<QoreProgram*> pgm_set_t;
1016  pgm_set_t pgm_set;
1017 
1018  // lock for pgm_set data structure (which is accessed from multiple threads when QorePrograms deregister themselves)
1019  QoreThreadLock pslock;
1020 
1021  ThreadData* td;
1022 
1023  DLLLOCAL void ref() {
1024  ROreference();
1025  }
1026 
1027  DLLLOCAL ~ThreadProgramData() {
1028  assert(pgm_set.empty());
1029  }
1030 
1031 public:
1032  DLLLOCAL ThreadProgramData(ThreadData* n_td) : td(n_td) {
1033  }
1034 
1035  DLLLOCAL void delProgram(QoreProgram* pgm);
1036  DLLLOCAL bool saveProgram(bool runtime, ExceptionSink* xsink);
1037  DLLLOCAL void del(ExceptionSink* xsink);
1038 
1039  DLLLOCAL void deref() {
1040  if (ROdereference())
1041  delete this;
1042  }
1043  DLLLOCAL int gettid();
1044 };
1045 
1046 class ThreadFrameBoundaryHelper {
1047 public:
1048  DLLLOCAL ThreadFrameBoundaryHelper(bool doit) : doit(doit) {
1049  if (doit) {
1050  //printd(5, "ThreadFrameBoundaryHelper::ThreadFrameBoundaryHelper: this:%p\n", this);
1051  thread_push_frame_boundary();
1052  }
1053  }
1054 
1055  DLLLOCAL ~ThreadFrameBoundaryHelper() {
1056  if (doit) {
1057  //printd(5, "ThreadFrameBoundaryHelper::~ThreadFrameBoundaryHelper: this:%p\n", this);
1058  thread_pop_frame_boundary();
1059  }
1060  }
1061 
1062 private:
1063  bool doit;
1064 };
1065 
1066 DLLLOCAL extern pthread_mutexattr_t ma_recursive;
1067 DLLLOCAL extern QoreRWLock lck_debug_program;
1068 
1069 #ifdef QORE_HAVE_THREAD_NAME
1070 DLLLOCAL void q_set_thread_name(const char* name);
1071 DLLLOCAL void q_get_thread_name(QoreString& str);
1072 #endif
1073 
1074 #endif
NT_OBJECT
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
QoreProgram
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only
Definition: QoreProgram.h:126
QORE_NUM_TYPES
#define QORE_NUM_TYPES
number of types implemented in the Qore library
Definition: node_types.h:90
QoreValue
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
QoreHashNode
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
NT_NOTHING
const qore_type_t NT_NOTHING
type value for QoreNothingNode
Definition: node_types.h:42
QoreClass
defines a Qore-language class
Definition: QoreClass.h:239
AbstractQoreNode::getType
DLLLOCAL qore_type_t getType() const
returns the data type
Definition: AbstractQoreNode.h:172
QoreListNode
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
int64
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260
QoreNamespace
contains constants, classes, and subnamespaces in QoreProgram objects
Definition: QoreNamespace.h:65
QoreReferenceCounter::ROdereference
DLLEXPORT bool ROdereference() const
atomically decrements the reference count
QoreString
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:81
gettid
DLLEXPORT int gettid() noexcept
QoreStackLocation::getStatement
virtual const DLLLOCAL AbstractStatement * getStatement() const =0
returns the statement for the call for internal Qore code
ExceptionSink::raiseException
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
QoreValue::discard
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values
ReferenceNode
parse type: reference to a lvalue expression
Definition: ReferenceNode.h:45
QoreObject
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition: QoreObject.h:61
ExceptionSink
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
QoreReferenceCounter::ROreference
DLLEXPORT void ROreference() const
atomically increments the reference count
QoreReferenceCounter
provides atomic reference counting to Qore objects
Definition: QoreReferenceCounter.h:44
QoreThreadLock
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
NT_LIST
const qore_type_t NT_LIST
type value for QoreListNode
Definition: node_types.h:50
getProgram
DLLEXPORT QoreProgram * getProgram()
returns the current QoreProgram
NT_HASH
const qore_type_t NT_HASH
type value for QoreHashNode
Definition: node_types.h:51
RootQoreNamespace
the root namespace of a QoreProgram object
Definition: QoreNamespace.h:335
QoreStringNode
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
AbstractQoreNode
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:54
qore_type_t
int16_t qore_type_t
used to identify unique Qore data and parse types (descendents of AbstractQoreNode)
Definition: common.h:70
QoreRWLock
provides a simple POSIX-threads-based read-write lock
Definition: QoreRWLock.h:47
QoreStackLocation
Stack location element abstract class.
Definition: ExceptionSink.h:410