Qore Programming Language  0.9.4.6
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 int init(QoreProgram& pgm, ExceptionSink& xsink);
226 
227  DLLLOCAL AbstractQoreNode* takeDel();
228 
229 protected:
230  DLLLOCAL void initClosure(const QoreProgramLocation* loc, QoreValue& c, const char* n);
231 };
232 
233 DLLLOCAL QoreValue do_op_background(const QoreValue left, ExceptionSink* xsink);
234 
235 // returns 0 if the last mark has been cleared, -1 if there are more marks to check
236 DLLLOCAL int purge_thread_resources_to_mark(ExceptionSink* xsink);
237 DLLLOCAL void purge_thread_resources(ExceptionSink* xsink);
238 DLLLOCAL void purge_pgm_thread_resources(const QoreProgram* pgm, ExceptionSink* xsink);
239 DLLLOCAL void mark_thread_resources();
240 DLLLOCAL void beginParsing(const char* file, void* ps = NULL, const char* src = nullptr, int offset = 0);
241 DLLLOCAL void* endParsing();
242 DLLLOCAL Context* get_context_stack();
243 DLLLOCAL void update_context_stack(Context* cstack);
244 
245 DLLLOCAL const QoreStackLocation* get_runtime_stack_location();
246 DLLLOCAL const QoreStackLocation* update_get_runtime_stack_location(QoreStackLocation* stack_loc,
247  const AbstractStatement*& current_stmt, QoreProgram*& current_pgm);
248 DLLLOCAL const QoreStackLocation* update_get_runtime_stack_builtin_location(QoreStackLocation* stack_loc,
249  const AbstractStatement*& current_stmt, QoreProgram*& current_pgm, const QoreProgramLocation*& old_runtime_loc);
250 DLLLOCAL void update_runtime_stack_location(const QoreStackLocation* stack_loc);
251 DLLLOCAL void update_runtime_stack_location(const QoreStackLocation* stack_loc, const QoreProgramLocation* runtime_loc);
252 
253 DLLLOCAL const QoreProgramLocation* get_runtime_location();
254 DLLLOCAL void update_get_runtime_statement_location(const AbstractStatement* stmt,
255  const QoreProgramLocation* loc, const AbstractStatement*& old_stmt, const QoreProgramLocation*& old_loc);
256 DLLLOCAL void update_runtime_statement_location(const AbstractStatement* stmt, const QoreProgramLocation* loc);
257 
258 DLLLOCAL void set_parse_file_info(QoreProgramLocation& loc);
259 DLLLOCAL const char* get_parse_code();
260 
261 DLLLOCAL const AbstractStatement* get_runtime_statement();
262 
263 DLLLOCAL const QoreTypeInfo* parse_set_implicit_arg_type_info(const QoreTypeInfo* ti);
264 DLLLOCAL const QoreTypeInfo* parse_get_implicit_arg_type_info();
265 
266 DLLLOCAL int64 parse_get_parse_options();
267 DLLLOCAL int64 runtime_get_parse_options();
268 
269 DLLLOCAL bool parse_check_parse_option(int64 o);
270 DLLLOCAL bool runtime_check_parse_option(int64 o);
271 
272 DLLLOCAL RootQoreNamespace* getRootNS();
273 DLLLOCAL void updateCVarStack(CVNode* ncvs);
274 DLLLOCAL CVNode* getCVarStack();
275 DLLLOCAL void updateVStack(VNode* nvs);
276 DLLLOCAL VNode* getVStack();
277 
278 //DLLLOCAL void setParseClass(QoreClass* c);
279 DLLLOCAL QoreClass* parse_get_class();
280 DLLLOCAL qore_class_private* parse_get_class_priv();
281 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);
282 DLLLOCAL void thread_set_class_and_ns(const qore_class_private* new_cls, qore_ns_private* new_ns);
283 DLLLOCAL void thread_set_ns(qore_ns_private* new_ns, qore_ns_private*& old_ns);
284 DLLLOCAL void thread_set_ns(qore_ns_private* new_ns);
285 DLLLOCAL qore_ns_private* parse_get_ns();
286 
287 DLLLOCAL void substituteObjectIfEqual(QoreObject* o);
288 DLLLOCAL QoreObject* substituteObject(QoreObject* o);
289 DLLLOCAL QoreException* catchSwapException(QoreException* e);
290 DLLLOCAL QoreException* catchGetException();
291 DLLLOCAL VLock* getVLock();
292 DLLLOCAL void end_signal_thread(ExceptionSink* xsink);
293 DLLLOCAL void delete_thread_local_data();
294 DLLLOCAL void parse_cond_push(bool mark = false);
295 DLLLOCAL bool parse_cond_else();
296 DLLLOCAL bool parse_cond_pop(const QoreProgramLocation* loc);
297 DLLLOCAL bool parse_cond_test(const QoreProgramLocation* loc);
298 DLLLOCAL void push_parse_options();
299 DLLLOCAL void parse_try_module_inc();
300 DLLLOCAL bool parse_try_module_dec(const QoreProgramLocation* loc);
301 DLLLOCAL unsigned parse_try_module_get();
302 DLLLOCAL void parse_try_module_set(unsigned c);
303 
304 DLLLOCAL void parse_push_name(const char* name);
305 DLLLOCAL std::string parse_pop_name();
306 
307 DLLLOCAL void set_module_context(QoreModuleContext* qmc);
308 DLLLOCAL QoreModuleContext* get_module_context();
309 DLLLOCAL QoreModuleDefContext* set_module_def_context(QoreModuleDefContext* qmd);
310 DLLLOCAL QoreModuleDefContext* get_module_def_context();
311 DLLLOCAL void parse_set_module_def_context_name(const char* name);
312 DLLLOCAL const char* set_user_module_context_name(const char* n);
313 DLLLOCAL const char* get_user_module_context_name();
314 DLLLOCAL const char* get_module_context_name();
315 
316 DLLLOCAL void parse_set_try_reexport(bool tr);
317 DLLLOCAL bool parse_get_try_reexport();
318 
319 DLLLOCAL void set_thread_tz(const AbstractQoreZoneInfo* tz);
320 DLLLOCAL const AbstractQoreZoneInfo* get_thread_tz(bool& set);
321 DLLLOCAL void clear_thread_tz();
322 
323 DLLLOCAL ThreadProgramData* get_thread_program_data();
324 DLLLOCAL ThreadLocalProgramData* get_thread_local_program_data();
325 
326 DLLLOCAL int thread_ref_set(const lvalue_ref* r);
327 DLLLOCAL void thread_ref_remove(const lvalue_ref* r);
328 
329 // pushes a new argv reference counter
330 DLLLOCAL void new_argv_ref();
331 
332 // increments the parse argv reference counter
333 DLLLOCAL void inc_argv_ref();
334 
335 // pushes an "ignore numeric reference" context
336 DLLLOCAL void push_ignore_numeric_argv_ref();
337 
338 // pops an "ignore numeric reference" context
339 DLLLOCAL void pop_ignore_numeric_argv_ref();
340 
341 // increments the parse argv reference counter for numeric references (ex: $1)
342 DLLLOCAL void inc_numeric_argv_ref();
343 
344 // gets the parse argv reference counter and pops the context
345 DLLLOCAL int get_pop_argv_ref();
346 
347 // clears the argv reference stack
348 DLLLOCAL void clear_argv_ref();
349 
350 DLLLOCAL int set_constant(ConstantEntry* ce);
351 DLLLOCAL void remove_constant(ConstantEntry* ce);
352 
353 DLLLOCAL QoreAbstractModule* set_reexport(QoreAbstractModule* m, bool current_reexport, bool& old_reexport);
354 DLLLOCAL void set_reexport(QoreAbstractModule* m, bool reexport);
355 
356 DLLLOCAL void parseSetCodeInfo(const char* parse_code, const QoreTypeInfo* returnTypeInfo, const char*& old_code, const QoreTypeInfo*& old_returnTypeInfo);
357 DLLLOCAL void parseRestoreCodeInfo(const char* parse_code, const QoreTypeInfo* returnTypeInfo);
358 // sets the new type and returns the old
359 DLLLOCAL const QoreTypeInfo* saveReturnTypeInfo(const QoreTypeInfo* returnTypeInfo);
360 DLLLOCAL const QoreTypeInfo* getReturnTypeInfo();
361 
362 DLLLOCAL const QoreTypeInfo* parse_get_return_type_info();
363 
364 DLLLOCAL QoreProgram* get_set_program_call_context(QoreProgram* new_pgm);
365 DLLLOCAL void set_program_call_context(QoreProgram* new_pgm);
366 
367 // issue #3242: make sure we can temporarily set any current lvar stack to nullptr when parsing out of order
368 class LVarStackBreakHelper {
369 public:
370  DLLLOCAL LVarStackBreakHelper();
371  DLLLOCAL ~LVarStackBreakHelper();
372 
373 private:
374  VNode* vnode;
375 };
376 
377 class ProgramCallContextHelper {
378 public:
379  DLLLOCAL ProgramCallContextHelper(QoreProgram* new_pgm)
380  : pgm(new_pgm ? get_set_program_call_context(new_pgm) : reinterpret_cast<QoreProgram*>(-1)) {
381  }
382 
383  DLLLOCAL ~ProgramCallContextHelper() {
384  if (pgm != reinterpret_cast<QoreProgram*>(-1)) {
385  set_program_call_context(pgm);
386  }
387  }
388 
389 private:
390  QoreProgram* pgm;
391 };
392 
393 class ModuleReExportHelper {
394 protected:
395  QoreAbstractModule* m;
396  bool reexport;
397 
398 public:
399  DLLLOCAL ModuleReExportHelper(QoreAbstractModule* mi, bool reexp);
400  DLLLOCAL ~ModuleReExportHelper();
401 };
402 
403 class QoreParseCountContextHelper {
404 protected:
405  unsigned count;
406 
407 public:
408  DLLLOCAL QoreParseCountContextHelper() : count(parse_try_module_get()) {
409  parse_try_module_set(0);
410  }
411 
412  DLLLOCAL ~QoreParseCountContextHelper() {
413  parse_try_module_set(count);
414  }
415 };
416 
417 class QoreProgramStackLocationHelper {
418 public:
419  DLLLOCAL QoreProgramStackLocationHelper(QoreStackLocation* stack_loc, const AbstractStatement*& current_stmt,
420  QoreProgram*& current_pgm) :
421  stack_loc(update_get_runtime_stack_location(stack_loc, current_stmt, current_pgm)) {
422  }
423 
424  DLLLOCAL ~QoreProgramStackLocationHelper() {
425  update_runtime_stack_location(stack_loc);
426  }
427 
428 protected:
429  const QoreStackLocation* stack_loc;
430 };
431 
432 class QoreInternalCallStackLocationHelperBase : public QoreStackLocation, public QoreProgramStackLocationHelper {
433 public:
434  DLLLOCAL QoreInternalCallStackLocationHelperBase() : QoreProgramStackLocationHelper(this, stmt, pgm) {
435  }
436 
437  DLLLOCAL virtual QoreProgram* getProgram() const {
438  return pgm;
439  }
440 
441  DLLLOCAL virtual const AbstractStatement* getStatement() const {
442  return stmt;
443  }
444 
445 protected:
446  const AbstractStatement* stmt;
447  QoreProgram* pgm;
448 };
449 
450 class QoreInternalCallStackLocationHelper : public QoreInternalCallStackLocationHelperBase {
451 public:
452  DLLLOCAL QoreInternalCallStackLocationHelper(const QoreProgramLocation& loc, const std::string& call,
453  qore_call_t call_type) : loc(loc), call(call), call_type(call_type) {
454  }
455 
457  DLLLOCAL virtual const QoreProgramLocation& getLocation() const {
458  return loc;
459  }
460 
462  DLLLOCAL virtual const std::string& getCallName() const {
463  return call;
464  }
465 
466  DLLLOCAL virtual qore_call_t getCallType() const {
467  return call_type;
468  }
469 
470 protected:
471  const QoreProgramLocation& loc;
472  const std::string call;
473  qore_call_t call_type;
474 };
475 
476 class QoreProgramLocationHelper {
477 public:
478  DLLLOCAL QoreProgramLocationHelper(const QoreProgramLocation* n_loc, const AbstractStatement* n_stat = nullptr) {
479  update_get_runtime_statement_location(n_stat, n_loc, statement, loc);
480  }
481 
482  DLLLOCAL ~QoreProgramLocationHelper() {
483  update_runtime_statement_location(statement, loc);
484  }
485 
486 protected:
487  const QoreProgramLocation* loc;
488  const AbstractStatement* statement;
489 };
490 
491 class QoreProgramOptionalLocationHelper {
492 public:
493  DLLLOCAL QoreProgramOptionalLocationHelper(const QoreProgramLocation* n_loc, const AbstractStatement* n_stat = nullptr) : restore((bool)n_loc) {
494  if (n_loc) {
495  update_get_runtime_statement_location(n_stat, n_loc, statement, loc);
496  }
497  }
498 
499  DLLLOCAL ~QoreProgramOptionalLocationHelper() {
500  if (restore) {
501  update_runtime_statement_location(statement, loc);
502  }
503  }
504 
505 protected:
506  const QoreProgramLocation* loc;
507  const AbstractStatement* statement;
508  bool restore;
509 };
510 
511 // allows for the parse lock for the current program to be acquired by binary modules
512 class CurrentProgramRuntimeParseContextHelper {
513 public:
514  // acquires the parse lock; if already acquired by another thread, then this call blocks until the lock can be acquired
515  DLLEXPORT CurrentProgramRuntimeParseContextHelper();
516  // releases the parse lock for the current program
517  DLLEXPORT ~CurrentProgramRuntimeParseContextHelper();
518 
519 private:
520  // not implemented
521  CurrentProgramRuntimeParseContextHelper(const CurrentProgramRuntimeParseContextHelper&) = delete;
522  void* operator new(size_t) = delete;
523 };
524 
525 // allows for implicit argument types to be set at parse time
526 class ParseImplicitArgTypeHelper {
527 public:
528  DLLLOCAL ParseImplicitArgTypeHelper(const QoreTypeInfo* ti) : ati(parse_set_implicit_arg_type_info(ti)) {
529  }
530 
531  DLLLOCAL ~ParseImplicitArgTypeHelper() {
532  parse_set_implicit_arg_type_info(ati);
533  }
534 
535 private:
536  const QoreTypeInfo* ati;
537 };
538 
539 // acquires a TID and thread entry, returns -1 if not successful
540 DLLLOCAL int get_thread_entry();
541 // acquires TID 0 and sets up the signal thread entry, always returns 0
542 DLLLOCAL int get_signal_thread_entry();
543 DLLLOCAL void deregister_signal_thread();
544 DLLLOCAL void register_thread(int tid, pthread_t ptid, QoreProgram* pgm, bool foreign = false);
545 DLLLOCAL void deregister_thread(int tid);
546 DLLLOCAL void delete_signal_thread();
547 
548 // returns 1 if data structure is already on stack, 0 if not (=OK)
549 DLLLOCAL int thread_push_container(const AbstractQoreNode* n);
550 DLLLOCAL void thread_pop_container(const AbstractQoreNode* n);
551 
552 // called when a StatementBlock has "on block exit" blocks
553 DLLLOCAL void pushBlock(block_list_t::iterator i);
554 // called when a StatementBlock has "on block exit" blocks
555 DLLLOCAL block_list_t::iterator popBlock();
556 // called by each "on_block_exit" statement to activate it's code for the block exit
557 DLLLOCAL void advanceOnBlockExit();
558 
559 DLLLOCAL LocalVarValue* thread_instantiate_lvar();
560 DLLLOCAL void thread_uninstantiate_lvar(ExceptionSink* xsink);
561 DLLLOCAL void thread_uninstantiate_self();
562 
563 DLLLOCAL void thread_set_closure_parse_env(ClosureParseEnvironment* cenv);
564 DLLLOCAL ClosureParseEnvironment* thread_get_closure_parse_env();
565 
566 DLLLOCAL ClosureVarValue* thread_instantiate_closure_var(const char* id, const QoreTypeInfo* typeInfo, QoreValue& nval, bool assign);
567 DLLLOCAL void thread_instantiate_closure_var(ClosureVarValue* cvar);
568 DLLLOCAL void thread_uninstantiate_closure_var(ExceptionSink* xsink);
569 DLLLOCAL ClosureVarValue* thread_find_closure_var(const char* id);
570 
571 DLLLOCAL ClosureVarValue* thread_get_runtime_closure_var(const LocalVar* id);
572 DLLLOCAL const QoreClosureBase* thread_set_runtime_closure_env(const QoreClosureBase* current);
573 
574 typedef std::vector<ClosureVarValue*> cvv_vec_t;
575 DLLLOCAL cvv_vec_t* thread_get_all_closure_vars();
576 
577 DLLLOCAL void thread_push_frame_boundary();
578 DLLLOCAL void thread_pop_frame_boundary();
579 
580 DLLLOCAL QoreHashNode* thread_get_local_vars(int frame, ExceptionSink* xsink);
581 // returns 0 = OK, 1 = no such variable, -1 exception setting variable
582 DLLLOCAL int thread_set_local_var_value(int frame, const char* name, const QoreValue& val, ExceptionSink* xsink);
583 // returns 0 = OK, 1 = no such variable, -1 exception setting variable
584 DLLLOCAL int thread_set_closure_var_value(int frame, const char* name, const QoreValue& val, ExceptionSink* xsink);
585 
586 DLLLOCAL int get_implicit_element();
587 DLLLOCAL int save_implicit_element(int n_element);
588 
589 DLLLOCAL VNode* update_get_vstack(VNode* vn);
590 DLLLOCAL void save_global_vnode(VNode* vn);
591 DLLLOCAL VNode* get_global_vnode();
592 
593 class QoreContainerHelper {
594  const AbstractQoreNode* n;
595  bool err;
596 
597 public:
598  DLLLOCAL QoreContainerHelper(const AbstractQoreNode* n_n) {
599  // FIXME! need to have an AbstactQoreNode::isContainer() function!
600  qore_type_t t = n_n ? n_n->getType() : NT_NOTHING;
601  if ((t == NT_LIST || t == NT_HASH || t == NT_OBJECT || t >= QORE_NUM_TYPES)) {
602  if (!thread_push_container(n_n)) {
603  n = n_n;
604  err = false;
605  }
606  else {
607  n = nullptr;
608  err = true;
609  }
610  }
611  else {
612  n = nullptr;
613  err = false;
614  }
615  }
616  DLLLOCAL ~QoreContainerHelper() {
617  if (n)
618  thread_pop_container(n);
619  }
620  DLLLOCAL operator bool () const {
621  return !err;
622  }
623 };
624 
625 DLLLOCAL const QoreListNode* thread_get_implicit_args();
626 
627 DLLLOCAL LocalVarValue* thread_find_lvar(const char* id);
628 
629 // to get the current runtime object
630 DLLLOCAL QoreObject* runtime_get_stack_object();
631 // to get the current runtime class
632 DLLLOCAL const qore_class_private* runtime_get_class();
633 DLLLOCAL void runtime_get_object_and_class(QoreObject*& obj, const qore_class_private*& qc);
634 // for methods that behave differently when called within the method itself (methodGate(), memberGate(), etc)
635 DLLLOCAL bool runtime_in_object_method(const char* name, const QoreObject* o);
636 
637 class CodeContextHelperBase {
638 private:
639  const char* old_code;
640  QoreObject* old_obj;
641  const qore_class_private* old_class;
642  QoreProgram* old_call_program_context;
643  bool do_ref,
644  do_program_context;
645 
646  ExceptionSink* xsink;
647 
648 public:
649  DLLLOCAL CodeContextHelperBase(const char* code, QoreObject* obj, const qore_class_private* c, ExceptionSink* xsink, bool ref_obj = true);
650  DLLLOCAL ~CodeContextHelperBase();
651 };
652 
653 class ObjectSubstitutionHelper {
654 private:
655  QoreObject* old_obj;
656  const qore_class_private* old_class;
657 
658 public:
659  DLLLOCAL ObjectSubstitutionHelper(QoreObject* obj, const qore_class_private* c);
660  DLLLOCAL ~ObjectSubstitutionHelper();
661 };
662 
663 class OptionalClassObjSubstitutionHelper {
664 public:
665  DLLLOCAL OptionalClassObjSubstitutionHelper(const qore_class_private* qc);
666  DLLLOCAL ~OptionalClassObjSubstitutionHelper();
667 
668 private:
669  QoreObject* old_obj;
670  const qore_class_private* old_class;
671  bool subst;
672 };
673 
674 class OptionalClassOnlySubstitutionHelper {
675 public:
676  DLLLOCAL OptionalClassOnlySubstitutionHelper(const qore_class_private* qc);
677  DLLLOCAL ~OptionalClassOnlySubstitutionHelper();
678 
679 private:
680  const qore_class_private* old_class;
681  bool subst;
682 };
683 
684 class OptionalObjectOnlySubstitutionHelper {
685 public:
686  DLLLOCAL OptionalObjectOnlySubstitutionHelper(QoreObject* obj);
687  DLLLOCAL ~OptionalObjectOnlySubstitutionHelper();
688 
689 private:
690  bool subst;
691  QoreObject* old_obj;
692 };
693 
694 class ThreadSafeLocalVarRuntimeEnvironmentHelper {
695 private:
696  const QoreClosureBase* prev;
697 
698 public:
699  DLLLOCAL ThreadSafeLocalVarRuntimeEnvironmentHelper(const QoreClosureBase* current);
700  DLLLOCAL ~ThreadSafeLocalVarRuntimeEnvironmentHelper();
701 };
702 
703 typedef std::map<const LocalVar*, ClosureVarValue*> cvar_map_t;
704 typedef std::set<ClosureVarValue*> cvv_set_t;
705 
706 class ThreadSafeLocalVarRuntimeEnvironment {
707 private:
708  cvar_map_t cmap;
709  cvv_set_t cvvset;
710 
711 public:
712  DLLLOCAL ThreadSafeLocalVarRuntimeEnvironment(const lvar_set_t* vlist);
713  DLLLOCAL ~ThreadSafeLocalVarRuntimeEnvironment();
714  DLLLOCAL ClosureVarValue* find(const LocalVar* id) const;
715  DLLLOCAL bool hasVar(ClosureVarValue* cvv) const;
716  DLLLOCAL void del(ExceptionSink* xsink);
717 
718  DLLLOCAL bool empty() {
719  return cmap.empty();
720  }
721 
722  DLLLOCAL const cvar_map_t& getMap() const {
723  return cmap;
724  }
725 };
726 
727 hashdecl ThreadLocalProgramData;
728 
729 class QoreProgramBlockParseOptionHelper {
730 public:
731  DLLLOCAL QoreProgramBlockParseOptionHelper(int64 n_po);
732  DLLLOCAL ~QoreProgramBlockParseOptionHelper();
733 
734 protected:
735  int64 po;
736 };
737 
738 class ProgramThreadCountContextHelper {
739 public:
740  DLLLOCAL ProgramThreadCountContextHelper(ExceptionSink* xsink, QoreProgram* pgm, bool runtime);
741  DLLLOCAL ~ProgramThreadCountContextHelper();
742  static ThreadLocalProgramData* getContextFrame(int& frame, ExceptionSink* xsink);
743  bool isFirstThreadLocalProgramData(const ThreadLocalProgramData* tlpd) const;
744 
745 protected:
746  QoreProgram* old_pgm = nullptr;
747  ThreadLocalProgramData* old_tlpd = nullptr;
748  ProgramThreadCountContextHelper* old_ctx = nullptr;
749  // frame count of tlpd when context is started
750  int save_frameCount = 0;
751  int old_frameCount;
752  bool restore = false;
753  bool init_tlpd = false;
754 };
755 
756 class ProgramRuntimeParseContextHelper {
757 protected:
758  QoreProgram* old_pgm;
759  bool restore;
760 
761 public:
762  DLLLOCAL ProgramRuntimeParseContextHelper(ExceptionSink* xsink, QoreProgram* pgm);
763  DLLLOCAL ~ProgramRuntimeParseContextHelper();
764 };
765 
766 // ensures the program is locked for parsing and that thread-local data is available for execution at parse commit time
767 class ProgramRuntimeParseCommitContextHelper {
768 protected:
769  QoreProgram* old_pgm;
770  ThreadLocalProgramData* old_tlpd;
771  bool restore;
772 
773 public:
774  DLLLOCAL ProgramRuntimeParseCommitContextHelper(ExceptionSink* xsink, QoreProgram* pgm);
775  DLLLOCAL ~ProgramRuntimeParseCommitContextHelper();
776 };
777 
778 class ProgramRuntimeParseAccessHelper {
779 protected:
780  QoreProgram* old_pgm;
781  bool restore;
782 
783 public:
784  DLLLOCAL ProgramRuntimeParseAccessHelper(ExceptionSink* xsink, QoreProgram* pgm);
785  DLLLOCAL ~ProgramRuntimeParseAccessHelper();
786 };
787 
788 class RuntimeReferenceHelperBase {
789 protected:
790  const lvalue_ref* ref;
791  ProgramThreadCountContextHelper pch;
792  ObjectSubstitutionHelper osh;
793  bool valid = true;
794 
795 public:
796  DLLLOCAL RuntimeReferenceHelperBase(const lvalue_ref& r, ExceptionSink* n_xsink)
797  : ref(&r), pch(n_xsink, r.pgm, true), osh(r.self, r.cls) {
798  //printd(5, "RuntimeReferenceHelperBase::RuntimeReferenceHelperBase() this: %p vexp: %p %s %d\n", this, r.vexp, get_type_name(r.vexp), get_node_type(r.vexp));
799  if (thread_ref_set(&r)) {
800  ref = nullptr;
801  n_xsink->raiseException("CIRCULAR-REFERENCE-ERROR", "a circular lvalue reference was detected");
802  valid = false;
803  }
804  }
805 
806  DLLLOCAL ~RuntimeReferenceHelperBase() {
807  if (ref)
808  thread_ref_remove(ref);
809  }
810 
811  DLLLOCAL operator bool() const {
812  return valid;
813  }
814 };
815 
816 class RuntimeReferenceHelper : public RuntimeReferenceHelperBase {
817 public:
818  DLLLOCAL RuntimeReferenceHelper(const ReferenceNode& r, ExceptionSink* n_xsink) : RuntimeReferenceHelperBase(*lvalue_ref::get(&r), n_xsink) {
819  }
820 
821  DLLLOCAL RuntimeReferenceHelper(const lvalue_ref& r, ExceptionSink* n_xsink) : RuntimeReferenceHelperBase(r, n_xsink) {
822  }
823 };
824 
825 class ArgvContextHelper {
826 private:
827  QoreListNode* old_argv;
828  ExceptionSink* xsink;
829 
830 public:
831  DLLLOCAL ArgvContextHelper(QoreListNode* argv, ExceptionSink* n_xsink);
832  // calls deref(xsink) on list in destructor
833  DLLLOCAL ~ArgvContextHelper();
834 };
835 
836 class SingleArgvContextHelper {
837 private:
838  QoreListNode* old_argv;
839  ExceptionSink* xsink;
840 
841 public:
842  // any reference in val will be overtaken by the SingleArgvContextHelper object
843  DLLLOCAL SingleArgvContextHelper(QoreValue val, ExceptionSink* n_xsink);
844  // calls deref(xsink) on list in destructor
845  DLLLOCAL ~SingleArgvContextHelper();
846 };
847 
848 class ImplicitElementHelper {
849 private:
850  int element;
851 
852 public:
853  DLLLOCAL ImplicitElementHelper(int n_element) : element(save_implicit_element(n_element)) {
854  }
855  DLLLOCAL ~ImplicitElementHelper() {
856  save_implicit_element(element);
857  }
858 };
859 
860 class CodeContextHelper : public CodeContextHelperBase {
861 public:
862  DLLLOCAL CodeContextHelper(ExceptionSink* xs, int t, const char* c, QoreObject* obj = nullptr, const qore_class_private* cls = nullptr, bool ref_obj = true) :
863  CodeContextHelperBase(c, obj, cls, xs, ref_obj) {
864  }
865 };
866 
867 DLLLOCAL void init_qore_threads();
868 DLLLOCAL QoreNamespace* get_thread_ns(QoreNamespace& qorens);
869 DLLLOCAL void delete_qore_threads();
870 DLLLOCAL QoreListNode* get_thread_list();
871 DLLLOCAL QoreHashNode* getAllCallStacks();
872 DLLLOCAL QoreListNode* qore_get_thread_call_stack();
873 
874 #if defined(QORE_HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE)
875 #define QORE_HAVE_GET_STACK_SIZE
876 #endif
877 
878 #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)
879 #define QORE_HAVE_THREAD_NAME
880 #endif
881 
882 class QorePThreadAttr {
883 private:
884  pthread_attr_t attr;
885 
886 public:
887  DLLLOCAL QorePThreadAttr() {
888  pthread_attr_init(&attr);
889  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
890  }
891 
892  DLLLOCAL ~QorePThreadAttr() {
893  //printd(2, "calling pthread_attr_destroy(%p)\n", &attr);
894  pthread_attr_destroy(&attr);
895  //printd(2, "returned from pthread_attr_destroy(%p)\n", &attr);
896  }
897 
898 #ifdef HAVE_PTHREAD_ATTR_GETSTACK
899  DLLLOCAL void getstack(void*& ptr, size_t& ssize) {
900  pthread_attr_getstack(&attr, &ptr, &ssize);
901  }
902 #endif
903 
904  DLLLOCAL size_t getstacksize() const {
905  size_t ssize;
906  pthread_attr_getstacksize(&attr, &ssize);
907  return ssize;
908  }
909 
910  DLLLOCAL int setstacksize(size_t ssize) {
911  return pthread_attr_setstacksize(&attr, ssize);
912  }
913 
914  DLLLOCAL pthread_attr_t* get_ptr() {
915  return &attr;
916  }
917 
918 #ifdef QORE_HAVE_GET_STACK_SIZE
919  DLLLOCAL static size_t getCurrentThreadStackSize() {
920  pthread_attr_t attr;
921  if (pthread_getattr_np(pthread_self(), &attr)) {
922  return 0;
923  }
924  ON_BLOCK_EXIT(pthread_attr_destroy, &attr);
925  size_t size = 0;
926  if (pthread_attr_getstacksize(&attr, &size)) {
927  return 0;
928  }
929  return size;
930  }
931 #endif
932 };
933 
934 DLLLOCAL extern QorePThreadAttr ta_default;
935 
936 #ifdef QORE_MANAGE_STACK
937 DLLLOCAL int check_stack(ExceptionSink* xsink);
938 #endif
939 
940 class ParseCodeInfoHelper {
941 private:
942  const char* parse_code;
943  const QoreTypeInfo* returnTypeInfo;
944 
945 public:
946  DLLLOCAL ParseCodeInfoHelper(const char* n_parse_code, const QoreTypeInfo* n_returnTypeInfo) {
947  parseSetCodeInfo(n_parse_code, n_returnTypeInfo, parse_code, returnTypeInfo);
948  }
949 
950  DLLLOCAL ~ParseCodeInfoHelper() {
951  parseRestoreCodeInfo(parse_code, returnTypeInfo);
952  }
953 };
954 
955 class NamespaceParseContextHelper {
956 private:
957  qore_ns_private* ns;
958  bool restore;
959 
960 public:
961  DLLLOCAL NamespaceParseContextHelper(qore_ns_private* n_ns) {
962  thread_set_ns(n_ns, ns);
963  restore = (ns != n_ns);
964  }
965 
966  DLLLOCAL ~NamespaceParseContextHelper() {
967  if (restore) {
968  thread_set_ns(ns);
969  }
970  }
971 };
972 
973 class OptionalNamespaceParseContextHelper {
974 private:
975  qore_ns_private* ns;
976  bool restore;
977 
978 public:
979  DLLLOCAL OptionalNamespaceParseContextHelper(qore_ns_private* n_ns) {
980  if (n_ns) {
981  thread_set_ns(n_ns, ns);
982  restore = (ns != n_ns);
983  } else {
984  restore = false;
985  }
986  }
987 
988  DLLLOCAL ~OptionalNamespaceParseContextHelper() {
989  if (restore) {
990  thread_set_ns(ns);
991  }
992  }
993 };
994 
995 class QoreParseClassHelper {
996 protected:
997  const qore_class_private* cls;
998  qore_ns_private* ns;
999  bool restore;
1000 
1001 public:
1002  DLLLOCAL QoreParseClassHelper(QoreClass* new_cls, qore_ns_private* new_ns = nullptr);
1003 
1004  DLLLOCAL ~QoreParseClassHelper();
1005 };
1006 
1007 class ThreadData;
1008 
1009 class ThreadProgramData : public QoreReferenceCounter {
1010 private:
1011  // for the set of QoreProgram objects we have local variables in
1012  typedef std::set<QoreProgram*> pgm_set_t;
1013  pgm_set_t pgm_set;
1014 
1015  // lock for pgm_set data structure (which is accessed from multiple threads when QorePrograms deregister themselves)
1016  QoreThreadLock pslock;
1017 
1018  ThreadData* td;
1019 
1020  DLLLOCAL void ref() {
1021  ROreference();
1022  }
1023 
1024  DLLLOCAL ~ThreadProgramData() {
1025  assert(pgm_set.empty());
1026  }
1027 
1028 public:
1029  DLLLOCAL ThreadProgramData(ThreadData* n_td) : td(n_td) {
1030  }
1031 
1032  DLLLOCAL void delProgram(QoreProgram* pgm);
1033  DLLLOCAL bool saveProgram(bool runtime, ExceptionSink* xsink);
1034  DLLLOCAL void del(ExceptionSink* xsink);
1035 
1036  DLLLOCAL void deref() {
1037  if (ROdereference())
1038  delete this;
1039  }
1040  DLLLOCAL int gettid();
1041 };
1042 
1043 class ThreadFrameBoundaryHelper {
1044 public:
1045  DLLLOCAL ThreadFrameBoundaryHelper(bool doit) : doit(doit) {
1046  if (doit) {
1047  //printd(5, "ThreadFrameBoundaryHelper::ThreadFrameBoundaryHelper: this:%p\n", this);
1048  thread_push_frame_boundary();
1049  }
1050  }
1051 
1052  DLLLOCAL ~ThreadFrameBoundaryHelper() {
1053  if (doit) {
1054  //printd(5, "ThreadFrameBoundaryHelper::~ThreadFrameBoundaryHelper: this:%p\n", this);
1055  thread_pop_frame_boundary();
1056  }
1057  }
1058 
1059 private:
1060  bool doit;
1061 };
1062 
1063 DLLLOCAL extern pthread_mutexattr_t ma_recursive;
1064 DLLLOCAL extern QoreRWLock lck_debug_program;
1065 
1066 #ifdef QORE_HAVE_THREAD_NAME
1067 DLLLOCAL void q_set_thread_name(const char* name);
1068 DLLLOCAL void q_get_thread_name(QoreString& str);
1069 #endif
1070 
1071 #endif
DLLLOCAL qore_type_t getType() const
returns the data type
Definition: AbstractQoreNode.h:172
This is the hash or associative list container type in Qore, dynamically allocated only...
Definition: QoreHashNode.h:50
Stack location element abstract class.
Definition: ExceptionSink.h:396
DLLEXPORT int gettid() noexcept
returns the current TID number
const qore_type_t NT_LIST
type value for QoreListNode
Definition: node_types.h:50
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:54
const qore_type_t NT_NOTHING
type value for QoreNothingNode
Definition: node_types.h:42
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
contains constants, classes, and subnamespaces in QoreProgram objects
Definition: QoreNamespace.h:64
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
Qore&#39;s string type supported by the QoreEncoding class.
Definition: QoreString.h:81
Qore&#39;s string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
DLLEXPORT QoreProgram * getProgram()
returns the current QoreProgram
the root namespace of a QoreProgram object
Definition: QoreNamespace.h:286
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
provides atomic reference counting to Qore objects
Definition: QoreReferenceCounter.h:44
defines a Qore-language class
Definition: QoreClass.h:239
parse type: reference to a lvalue expression
Definition: ReferenceNode.h:45
const qore_type_t NT_HASH
type value for QoreHashNode
Definition: node_types.h:51
#define QORE_NUM_TYPES
number of types implemented in the Qore library
Definition: node_types.h:90
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only ...
Definition: QoreProgram.h:126
the implementation of Qore&#39;s object data type, reference counted, dynamically-allocated only ...
Definition: QoreObject.h:61
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:46
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
int16_t qore_type_t
used to identify unique Qore data and parse types (descendents of AbstractQoreNode) ...
Definition: common.h:70
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:47
provides a simple POSIX-threads-based read-write lock
Definition: QoreRWLock.h:47
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values ...