Qore Programming Language  0.9.4.6
QoreObjectIntern.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  QoreObjectIntern.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2020 Qore Technologies, s.r.o.
8 
9  Permission is hereby granted, free of charge, to any person obtaining a
10  copy of this software and associated documentation files (the "Software"),
11  to deal in the Software without restriction, including without limitation
12  the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  and/or sell copies of the Software, and to permit persons to whom the
14  Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  DEALINGS IN THE SOFTWARE.
26 
27  Note that the Qore library is released under a choice of three open-source
28  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29  information.
30 */
31 
32 #ifndef _QORE_QOREOBJECTINTERN_H
33 
34 #define _QORE_QOREOBJECTINTERN_H
35 
36 #include "qore/intern/VRMutex.h"
37 
38 #include <cassert>
39 #include <cstdlib>
40 #include <cstring>
41 #include <map>
42 #include <set>
43 #include <vector>
44 
45 //#define _QORE_CYCLE_CHECK 1
46 #ifdef _QORE_CYCLE_CHECK
47 #define QORE_DEBUG_OBJ_REFS 0
48 #define QRO_LVL 0
49 #else
50 #define QORE_DEBUG_OBJ_REFS 5
51 #define QRO_LVL 1
52 #endif
53 
54 #include "qore/intern/QoreClassIntern.h"
55 #include "qore/intern/RSection.h"
56 #include "qore/intern/RSet.h"
57 
58 #define OS_OK 0
59 #define OS_DELETED -1
60 
61 // object access constants
62 #define QOA_OK 0
63 #define QOA_PRIV_ERROR 1
64 #define QOA_PUB_ERROR 2
65 
66 class LValueHelper;
67 
68 class lthash {
69 public:
70  DLLLOCAL bool operator()(char* s1, char* s2) const {
71  return memcmp(s1, s2, SH_SIZE) < 0;
72  }
73 };
74 
75 // per-class internal data
76 typedef std::map<char*, QoreHashNode*, lthash> cdmap_t;
77 
78 /*
79  Qore internal class data is stored against the object with this data structure
80  against its qore_classid_t (class ID). In a class hierarchy, for private data
81  that is actually a C++ subclass of Qore parent classes, then we save the same
82  private data against the qore class IDs of the parent classes, but we set the
83  flag to true, meaning that we will not delete the private data when
84  the parent classes' destructors are run, but rather only when the subclass that
85  actually owns data has its turn to destroy private object data.
86 
87  So basically, the second boolean flag just means - does this class ID actually
88  own the private data or not - if it's false, then it does not actually own the data,
89  but is compatible with the data, so parent class builtin (C++) methods will get
90  passed this private data as if it belonged to this class and as if it were saved
91  directly to the object in the class' constructor.
92 
93  please note that this flag is called the "virtual" flag elsewhere in the code here,
94  meaning that the data only "virtually" belongs to the class
95  */
96 typedef std::pair<AbstractPrivateData*, bool> private_pair_t;
97 
98 // mapping from qore class ID to the object data
99 typedef std::map<qore_classid_t, private_pair_t> keymap_t;
100 
101 // for objects with multiple classes, private data has to be keyed
102 class KeyList {
103 private:
104  keymap_t keymap;
105 
106 public:
107  DLLLOCAL AbstractPrivateData* getReferencedPrivateData(qore_classid_t key) const {
108  keymap_t::const_iterator i = keymap.find(key);
109  if (i == keymap.end())
110  return 0;
111 
112  AbstractPrivateData* apd = i->second.first;
113  apd->ref();
114  return apd;
115  }
116 
117  DLLLOCAL void addToString(QoreString* str) const {
118  for (keymap_t::const_iterator i = keymap.begin(), e = keymap.end(); i != e; ++i)
119  str->sprintf("%d=<%p>, ", i->first, i->second.first);
120  }
121 
122  DLLLOCAL void derefAll(ExceptionSink* xsink) const {
123  for (keymap_t::const_iterator i = keymap.begin(), e = keymap.end(); i != e; ++i)
124  if (!i->second.second)
125  i->second.first->deref(xsink);
126  }
127 
128  DLLLOCAL AbstractPrivateData* getAndClearPtr(qore_classid_t key) {
129  keymap_t::iterator i = keymap.find(key);
130  //printd(5, "KeyList::getAndClearPtr this: %p, key: %d, end: %d\n", this, key, i == keymap.end());
131  if (i == keymap.end() || i->second.second) {
132  //printd(5, "KeyList::getAndClearPtr second: %d\n", i->second.second);
133  return nullptr;
134  }
135  //printd(5, "KeyList::getAndClearPtr first: %p\n", i->second.first);
136  // we must clear the private data when this function is called or a crash will result
137  AbstractPrivateData* rv = i->second.first;
138  keymap.erase(i);
139  return rv;
140  }
141 
142  DLLLOCAL AbstractPrivateData* getAndRemovePtr(qore_classid_t key) {
143  keymap_t::iterator i = keymap.find(key);
144  //printd(5, "KeyList::getAndRemovePtr this: %p, key: %d, end: %d\n", this, key, i == keymap.end());
145  if (i == keymap.end() || i->second.second) {
146  //printd(5, "KeyList::getAndRemovePtr second: %d\n", i->second.second);
147  return 0;
148  }
149  AbstractPrivateData* rv = i->second.first;
150  //printd(5, "KeyList::getAndRemovePtr first: %p\n", i->second.first);
151  i->second.first = 0;
152  return rv;
153  }
154 
155  DLLLOCAL void insert(qore_classid_t key, AbstractPrivateData* pd) {
156  assert(pd);
157  assert(keymap.find(key) == keymap.end());
158  //printd(5, "KeyList::insert this: %p, key: %d, pd: %p\n", this, key, pd);
159  keymap.insert(std::make_pair(key, std::make_pair(pd, false)));
160  }
161 
162  DLLLOCAL void insertVirtual(qore_classid_t key, AbstractPrivateData* pd) {
163  assert(pd);
164  //printd(5, "KeyList::insertVirtual this: %p, key: %d, pd: %p, test: %d\n", this, key, pd, keymap.find(key) == keymap.end());
165  if (keymap.find(key) == keymap.end())
166  keymap.insert(std::make_pair(key, std::make_pair(pd, true)));
167  }
168 };
169 
170 class VRMutex;
171 
172 class qore_object_private : public RObject {
173 public:
174  const QoreClass* theclass;
175  int status = OS_OK;
176 
177  KeyList* privateData = nullptr;
178  // member data
179  QoreHashNode* data;
180  QoreProgram* pgm;
181  cdmap_t* cdmap = nullptr;
182 
183  // used for garbage collection
184  mutable unsigned obj_count = 0;
185 
186  mutable VRMutex gate;
187 
188  int scan_private_data = 0;
189 
190  bool system_object, delete_blocker_run, in_destructor;
191  bool recursive_ref_found;
192 
193  QoreObject* obj;
194 
195  DLLLOCAL qore_object_private(QoreObject* n_obj, const QoreClass *oc, QoreProgram* p, QoreHashNode* n_data);
196 
197  DLLLOCAL ~qore_object_private();
198 
199  DLLLOCAL void incScanPrivateData();
200  DLLLOCAL void decScanPrivateData();
201 
202  DLLLOCAL void plusEquals(const AbstractQoreNode* v, AutoVLock& vl, ExceptionSink* xsink) {
203  if (!v)
204  return;
205 
206  // do not need ensure_unique() for objects
207  if (v->getType() == NT_OBJECT)
208  merge(*const_cast<QoreObject*>(reinterpret_cast<const QoreObject*>(v))->priv, vl, xsink);
209  else if (v->getType() == NT_HASH)
210  merge(reinterpret_cast<const QoreHashNode*>(v), vl, xsink);
211  }
212 
213  DLLLOCAL void merge(qore_object_private& o, AutoVLock& vl, ExceptionSink* xsink);
214 
215  DLLLOCAL void merge(const QoreHashNode* h, AutoVLock& vl, ExceptionSink* xsink);
216 
217  DLLLOCAL void mergeIntern(ExceptionSink* xsink, const QoreHashNode* h, bool& check_recursive, ReferenceHolder<QoreListNode>& holder, const qore_class_private* class_ctx, const QoreHashNode* new_internal_data = 0);
218 
219  DLLLOCAL QoreHashNode* copyData(ExceptionSink* xsink) const;
220 
221  DLLLOCAL int getLValue(const char* key, LValueHelper& lvh, const qore_class_private* class_ctx, bool for_remove, ExceptionSink* xsink);
222 
223  DLLLOCAL QoreStringNode* firstKey(ExceptionSink* xsink) {
224  // get the current class context
225  const qore_class_private* class_ctx = runtime_get_class();
226  if (class_ctx && !qore_class_private::runtimeCheckPrivateClassAccess(*theclass, class_ctx))
227  class_ctx = 0;
228 
229  QoreAutoVarRWReadLocker al(rml);
230 
231  if (status == OS_DELETED) {
232  makeAccessDeletedObjectException(xsink, theclass->getName());
233  return 0;
234  }
235 
236  if (class_ctx) {
237  const char* str = data->getFirstKey();
238  //printd(5, "qore_object_private::firstKey() got %p (%s)\n", str, str ? str : "<null>");
239  return !str ? 0 : new QoreStringNode(str);
240  }
241 
242  // get first accessible non-internal member
243  ConstHashIterator hi(data);
244  while (hi.next()) {
245  //printd(5, "qore_object_private::firstKey() checking '%s'\n", hi.getKey());
246  const qore_class_private* member_class_ctx = nullptr;
247  if (!checkMemberAccessIntern(hi.getKey(), false, class_ctx, member_class_ctx))
248  return new QoreStringNode(hi.getKey());
249  //printd(5, "qore_object_private::firstKey() skipping '%s' (private)\n", hi.getKey());
250  }
251 
252  return 0;
253  }
254 
255  DLLLOCAL QoreStringNode* lastKey(ExceptionSink* xsink) {
256  // get the current class context
257  const qore_class_private* class_ctx = runtime_get_class();
258  if (class_ctx && !qore_class_private::runtimeCheckPrivateClassAccess(*theclass, class_ctx))
259  class_ctx = 0;
260 
261  QoreAutoVarRWReadLocker al(rml);
262 
263  if (status == OS_DELETED) {
264  makeAccessDeletedObjectException(xsink, theclass->getName());
265  return 0;
266  }
267 
268  if (class_ctx) {
269  const char* str = data->getLastKey();
270  return !str ? 0 : new QoreStringNode(str);
271  }
272 
273  // get last accessible non-internal member
274  ReverseConstHashIterator hi(data);
275  while (hi.next()) {
276  const qore_class_private* member_class_ctx = nullptr;
277  if (!checkMemberAccessIntern(hi.getKey(), false, class_ctx, member_class_ctx))
278  return new QoreStringNode(hi.getKey());
279  }
280 
281  return 0;
282  }
283 
284  DLLLOCAL QoreHashNode* getSlice(const QoreListNode* l, ExceptionSink* xsink) const;
285 
286  DLLLOCAL int checkMemberAccessIntern(const char* mem, bool has_public_members, const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx) const {
287  assert(!member_class_ctx);
288 
289  const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
290  const QoreMemberInfo* info = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
291  if (!info) {
292  return has_public_members ? QOA_PUB_ERROR : QOA_OK;
293  }
294  member_class_ctx = info->getClassContext(class_ctx);
295  return ((info->access > Public) && !class_ctx) ? QOA_PRIV_ERROR : QOA_OK;
296  }
297 
298  // must be called in the object read lock
299  DLLLOCAL const QoreHashNode* getInternalData(const qore_class_private* class_ctx) const {
300  if (!cdmap)
301  return nullptr;
302  cdmap_t::const_iterator i = cdmap->find(class_ctx->getHash());
303  return i != cdmap->end() ? i->second : nullptr;
304  }
305 
306  // must be called in the object read lock
307  DLLLOCAL QoreHashNode* getInternalData(const qore_class_private* class_ctx) {
308  if (!cdmap)
309  return nullptr;
310  cdmap_t::iterator i = cdmap->find(class_ctx->getHash());
311  return i != cdmap->end() ? i->second : nullptr;
312  }
313 
314  // must be called in the object write lock
315  DLLLOCAL QoreHashNode* getCreateInternalData(const qore_class_private* class_ctx) {
316  if (cdmap) {
317  cdmap_t::iterator i = cdmap->find(class_ctx->getHash());
318  if (i != cdmap->end())
319  return i->second;
320  } else
321  cdmap = new cdmap_t;
322 
323  QoreHashNode* id = new QoreHashNode(autoTypeInfo);
324  cdmap->insert(cdmap_t::value_type(class_ctx->getHash(), id));
325  return id;
326  }
327 
328  // issue #3901: perform a shallow copy of private:internal data when executing a copy method
329  DLLLOCAL void copyInternalData(const qore_object_private& old) {
330  assert(!cdmap);
331  if (!old.cdmap) {
332  return;
333  }
334  cdmap = new cdmap_t;
335  for (auto& i : *old.cdmap) {
336  cdmap->insert(cdmap_t::value_type(i.first, i.second->copy()));
337  }
338  }
339 
340  DLLLOCAL void setValue(const char* key, QoreValue val, ExceptionSink* xsink);
341 
342  DLLLOCAL void setValueIntern(const qore_class_private* class_ctx, const char* key, QoreValue val, ExceptionSink* xsink);
343 
344  DLLLOCAL int checkMemberAccess(const char* mem, const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx) const {
345  assert(!member_class_ctx);
346 
347  const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
348  const QoreMemberInfo* info = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
349  if (!info) {
350  return theclass->runtimeHasPublicMembersInHierarchy() ? QOA_PUB_ERROR : QOA_OK;
351  }
352  member_class_ctx = info->getClassContext(class_ctx);
353  return ((info->access > Public) && !class_ctx) ? QOA_PRIV_ERROR : QOA_OK;
354  }
355 
356  DLLLOCAL int checkMemberAccess(const char* mem, const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx, ExceptionSink* xsink) const {
357  int rc = checkMemberAccess(mem, class_ctx, member_class_ctx);
358  if (!rc) {
359  return 0;
360  }
361 
362  if (rc == QOA_PRIV_ERROR) {
363  doPrivateException(mem, xsink);
364  }
365  else {
366  doPublicException(mem, xsink);
367  }
368  return -1;
369  }
370 
371  DLLLOCAL int checkMemberAccessGetTypeInfo(ExceptionSink* xsink, const char* mem, const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx, const QoreTypeInfo*& typeInfo) const {
372  assert(!member_class_ctx);
373  const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
374  const QoreMemberInfo* mi = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
375  if (mi) {
376  if (mi->access > Public && !class_ctx) {
377  doPrivateException(mem, xsink);
378  return -1;
379  }
380 
381  member_class_ctx = mi->getClassContext(class_ctx);
382  typeInfo = mi->getTypeInfo();
383  return 0;
384  }
385 
386  // member is not declared
387  if (theclass->runtimeHasPublicMembersInHierarchy()) {
388  doPublicException(mem, xsink);
389  return -1;
390  }
391  return 0;
392  }
393 
394  DLLLOCAL QoreValue takeMember(ExceptionSink* xsink, const char* mem, bool check_access = true);
395 
396  DLLLOCAL QoreValue takeMember(LValueHelper& lvh, const char* mem);
397 
398  DLLLOCAL void takeMembers(QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l);
399 
400  DLLLOCAL QoreValue getReferencedMemberNoMethod(const char* mem, ExceptionSink* xsink) const;
401 
402  // lock not held on entry
403  DLLLOCAL void doDeleteIntern(ExceptionSink* xsink) {
404  printd(5, "qore_object_private::doDeleteIntern() execing destructor() obj: %p\n", obj);
405 
406  // increment reference count temporarily for destructor
407  {
408  AutoLocker slr(rlck);
409  ++obj->references;
410  }
411 
412  theclass->execDestructor(obj, xsink);
413 
414  cdmap_t* cdm;
415  QoreHashNode* td;
416  {
417  QoreAutoVarRWWriteLocker al(rml);
418  assert(status != OS_DELETED);
419  assert(data);
420  status = OS_DELETED;
421 
422  cdm = cdmap;
423  cdmap = 0;
424 
425  td = data;
426  data = 0;
427 
428  removeInvalidateRSetIntern();
429  }
430 
431  cleanup(xsink, td, cdm);
432 
433  obj->deref(xsink);
434  }
435 
436  DLLLOCAL void cleanup(ExceptionSink* xsink, QoreHashNode* td, cdmap_t* cdm) {
437  if (privateData) {
438  printd(5, "qore_object_private::cleanup() this: %p privateData: %p\n", this, privateData);
439  delete privateData;
440 #ifdef DEBUG
441  privateData = nullptr;
442 #endif
443  }
444 
445  td->clear(xsink, true);
446  td->deref(xsink);
447 
448  if (cdm) {
449  for (auto& i : *cdm) {
450  i.second->clear(xsink, true);
451  i.second->deref(xsink);
452  }
453  delete cdm;
454  }
455  }
456 
457  // this method is called when there is an exception in a constructor and the object should be deleted
458  DLLLOCAL void obliterate(ExceptionSink* xsink) {
459  printd(5, "qore_object_private::obliterate() obj: %p class: %s %d->%d\n", obj, theclass->getName(), obj->references.load(), obj->references.load() - 1);
460 
461 #ifdef QORE_DEBUG_OBJ_REFS
462  printd(QORE_DEBUG_OBJ_REFS, "qore_object_private::obliterate() obj: %p class: %s: references %d->%d\n", obj, theclass->getName(), obj->references.load(), obj->references.load() - 1);
463 #endif
464 
465  {
466  AutoLocker slr(rlck);
467  if (--obj->references)
468  return;
469  }
470 
471  {
472  QoreSafeVarRWWriteLocker sl(rml);
473 
474  if (in_destructor || status != OS_OK) {
475  printd(5, "qore_object_private::obliterate() obj: %p data: %p in_destructor: %d status: %d\n", obj, data, in_destructor, status);
476  //printd(5, "Object lock %p unlocked (safe)\n", &rml);
477  sl.unlock();
478  tDeref();
479  return;
480  }
481 
482  //printd(5, "Object lock %p locked (safe)\n", &rml);
483  printd(5, "qore_object_private::obliterate() obj: %p class: %s\n", obj, theclass->getName());
484 
485  status = OS_DELETED;
486  cdmap_t* cdm = cdmap;
487  cdmap = 0;
488  QoreHashNode* td = data;
489  data = 0;
490 
491  removeInvalidateRSetIntern();
492 
493  //printd(5, "Object lock %p unlocked (safe)\n", &rml);
494  sl.unlock();
495 
496  if (privateData)
497  privateData->derefAll(xsink);
498 
499  cleanup(xsink, td, cdm);
500  }
501  tDeref();
502  }
503 
504  DLLLOCAL void doPrivateException(const char* mem, ExceptionSink* xsink) const {
505  xsink->raiseException("PRIVATE-MEMBER", "'%s' is a private member of class '%s'", mem, theclass->getName());
506  }
507 
508  DLLLOCAL void doPublicException(const char* mem, ExceptionSink* xsink) const {
509  xsink->raiseException("INVALID-MEMBER", "'%s' is not a registered member of class '%s'", mem, theclass->getName());
510  }
511 
512  DLLLOCAL virtual const char* getName() const {
513  return theclass->getName();
514  }
515 
516  DLLLOCAL virtual void deleteObject() {
517  delete obj;
518  }
519 
520  DLLLOCAL virtual bool isValidImpl() const {
521  if (status != OS_OK || in_destructor) {
522  printd(QRO_LVL, "qore_object_intern::isValidImpl() this: %p cannot delete graph obj status: %d in_destructor: %d\n", this, status, in_destructor);
523  return false;
524  }
525  return true;
526  }
527 
528  DLLLOCAL virtual bool scanMembersIntern(RSetHelper& rsh, QoreHashNode* odata);
529 
530  DLLLOCAL virtual bool scanMembers(RSetHelper& rsh);
531 
532  // always called in the rsection lock
533  DLLLOCAL virtual bool needsScan(bool scan_now) {
534  assert(rml.hasRSectionLock());
535  printd(5, "qore_object_private::needsScan() scan_count: %d scan_private_data: %d scan_now: %d\n",
536  getScanCount(), scan_private_data, scan_now);
537 
538  // the status cannot change while this lock is held
539  if ((!getScanCount() && !scan_private_data) || status != OS_OK) {
540  return false;
541  }
542 
543  {
544  AutoLocker al(rlck);
545  if (deferred_scan) {
546  if (!rrefs && scan_now) {
547  deferred_scan = false;
548  return true;
549  }
550  return false;
551  }
552  if (!rrefs) {
553  return true;
554  }
555  deferred_scan = true;
556  // if there is no rset, our job is done
557  if (!rset && !scan_private_data) {
558  return false;
559  }
560  // if we have an rset, then we need to invalidate it and ensure that
561  // rrefs does not go to zero until this is done
562  rref_wait = true;
563  }
564 
565  removeInvalidateRSetIntern();
566  AutoLocker al(rlck);
567  rref_wait = false;
568  if (rref_waiting) {
569  rcond.broadcast();
570  }
571 
572  return false;
573  }
574 
575  DLLLOCAL void mergeDataToHash(QoreHashNode* hash, ExceptionSink* xsink) const;
576 
577  DLLLOCAL void setPrivate(qore_classid_t key, AbstractPrivateData* pd) {
578  if (!privateData)
579  privateData = new KeyList;
580  //printd(5, "qore_object_private::setPrivate() this: %p 2:privateData: %p (%s) key: %d pd: %p\n", this, privateData, theclass->getName(), key, pd);
581  privateData->insert(key, pd);
582  addVirtualPrivateData(key, pd);
583  }
584 
585  // add virtual IDs for private data to class list
586  DLLLOCAL void addVirtualPrivateData(qore_classid_t key, AbstractPrivateData* apd) {
587  // first get parent class corresponding to "key"
588  QoreClass* qc = theclass->getClass(key);
589 
590  //printd(5, "qore_object_private::addVirtualPrivateData() this: %p privateData: %p key: %d apd: %p qc: %p '%s'\n", this, privateData, key, apd, qc, qc->getName());
591  assert(qc);
592  BCSMList* sml = qc->getBCSMList();
593  //printd(5, "qore_object_private::addVirtualPrivateData() this: %p qc: %p '%s' sml: %p\n", this, qc, qc->getName(), sml);
594  if (!sml)
595  return;
596 
597  for (class_list_t::const_iterator i = sml->begin(), e = sml->end(); i != e; ++i) {
598  //printd(5, "qore_object_private::addVirtualPrivateData() this: %p i: %p '%s' key: %d virt: %s\n", this, i->first, i->first->getName(), i->first->getID(), i->second ? "true" : "false");
599  if (i->second)
600  privateData->insertVirtual(i->first->getID(), apd);
601  }
602  }
603 
604  DLLLOCAL AbstractPrivateData* getAndRemovePrivateData(qore_classid_t key, ExceptionSink* xsink) {
605  QoreSafeVarRWWriteLocker sl(rml);
606  return privateData ? privateData->getAndRemovePtr(key) : nullptr;
607  }
608 
609  DLLLOCAL AbstractPrivateData* getReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
610 
611  DLLLOCAL AbstractPrivateData* tryGetReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
612 
613  DLLLOCAL QoreValue evalBuiltinMethodWithPrivateData(const QoreMethod& method, const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink);
614 
615  // no locking necessary; if class_ctx is non-null, an internal member is being initialized
616  DLLLOCAL QoreValue& getMemberValueRefForInitialization(const char* member, const qore_class_private* class_ctx);
617 
619 
623  DLLLOCAL QoreHashNode* getRuntimeMemberHash(ExceptionSink* xsink) const;
624 
625  DLLLOCAL void incScanCount(int dt) {
626  assert(dt);
627  assert(obj_count || dt > 0);
628  //printd(5, "qore_object_private::incScanCount() this: %p dt: %d: %d -> %d\n", this, dt, obj_count, obj_count + dt);
629  obj_count += dt;
630  }
631 
632  DLLLOCAL unsigned getScanCount() const {
633  return obj_count;
634  }
635 
636  DLLLOCAL VRMutex* getGate() const {
637  return &gate;
638  }
639 
640  /*
641  DLLLOCAL static bool hackId(const QoreObject& obj) {
642  if (!obj.priv->data)
643  return false;
644  const AbstractQoreNode* n = obj.priv->data->getKeyValue("name");
645  if (n && n->getType() == NT_STRING && strstr(reinterpret_cast<const QoreStringNode*>(n)->getBuffer(), "http-test"))
646  return true;
647  return false;
648  }
649  */
650 
651  // custom reference handler - unlocked
654  DLLLOCAL void customRefIntern(bool real);
655 
656  // custom dereference handler - unlocked
659  DLLLOCAL void customDeref(bool real, ExceptionSink* xsink);
660 
661  DLLLOCAL int startCall(const char* mname, ExceptionSink* xsink);
662 
663  DLLLOCAL void endCall(ExceptionSink* xsink);
664 
665  // increments the real reference count without incrementing the actual reference count
666  // (i.e. turns the current not real reference into a "real" reference; one that cannot
667  // participate in recursive graphs)
668  DLLLOCAL void setRealReference();
669 
670  // decrements the real reference count without decrementing the actual reference count
671  DLLLOCAL void unsetRealReference();
672 
673  DLLLOCAL const char* getClassName() const {
674  return theclass->getName();
675  }
676 
677  DLLLOCAL static QoreValue evalBuiltinMethodWithPrivateData(QoreObject& obj, const QoreMethod& method, const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) {
678  return obj.priv->evalBuiltinMethodWithPrivateData(method, meth, args, rtflags, xsink);
679  }
680 
681  DLLLOCAL static qore_object_private* get(QoreObject& obj) {
682  return obj.priv;
683  }
684 
685  DLLLOCAL static const qore_object_private* get(const QoreObject& obj) {
686  return obj.priv;
687  }
688 
689  DLLLOCAL static QoreValue takeMember(QoreObject& obj, ExceptionSink* xsink, const char* mem, bool check_access = true) {
690  return obj.priv->takeMember(xsink, mem, check_access);
691  }
692 
693  DLLLOCAL static QoreValue takeMember(QoreObject& obj, LValueHelper& lvh, const char* mem) {
694  return obj.priv->takeMember(lvh, mem);
695  }
696 
697  DLLLOCAL static void takeMembers(QoreObject& o, QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l) {
698  o.priv->takeMembers(rv, lvh, l);
699  }
700 
701  DLLLOCAL static int getLValue(const QoreObject& obj, const char* key, LValueHelper& lvh, const qore_class_private* class_ctx, bool for_remove, ExceptionSink* xsink) {
702  return obj.priv->getLValue(key, lvh, class_ctx, for_remove, xsink);
703  }
704 
705  DLLLOCAL static void plusEquals(QoreObject* obj, const AbstractQoreNode* v, AutoVLock& vl, ExceptionSink* xsink) {
706  obj->priv->plusEquals(v, vl, xsink);
707  }
708 
709  DLLLOCAL static QoreStringNode* firstKey(QoreObject* obj, ExceptionSink* xsink) {
710  return obj->priv->firstKey(xsink);
711  }
712 
713  DLLLOCAL static QoreStringNode* lastKey(QoreObject* obj, ExceptionSink* xsink) {
714  return obj->priv->lastKey(xsink);
715  }
716 
717  DLLLOCAL static unsigned getScanCount(const QoreObject& o) {
718  return o.priv->getScanCount();
719  }
720 
721  DLLLOCAL static void incScanCount(const QoreObject& o, int dt) {
722  o.priv->incScanCount(dt);
723  }
724 };
725 
726 class qore_object_lock_handoff_helper {
727 private:
728  qore_object_private* pobj;
729  AutoVLock& vl;
730 
731 public:
732  DLLLOCAL qore_object_lock_handoff_helper(qore_object_private* n_pobj, AutoVLock& n_vl) : pobj(n_pobj), vl(n_vl) {
733  if (pobj->obj == vl.getObject()) {
734  assert(vl.getRWL() == &pobj->rml);
735  vl.clear();
736  return;
737  }
738 
739  // reference current object
740  pobj->obj->tRef();
741 
742  // unlock previous lock and release from AutoVLock structure
743  vl.del();
744 
745  // lock current object
746  pobj->rml.wrlock();
747  }
748 
749  DLLLOCAL ~qore_object_lock_handoff_helper() {
750  // unlock if lock not saved in AutoVLock structure
751  if (pobj) {
752  //printd(5, "Object lock %p unlocked (handoff)\n", &pobj->rml);
753  pobj->rml.unlock();
754  pobj->obj->tDeref();
755  }
756  }
757 
758  DLLLOCAL void stayLocked() {
759  vl.set(pobj->obj, &pobj->rml);
760  pobj = 0;
761  }
762 };
763 
764 #endif
DLLEXPORT QoreClass * getClass(qore_classid_t cid) const
returns a pointer to the QoreClass object representing the class ID passed if it exists in the class ...
AutoVLock is a container for safely managing global variable and object lock handovers, required for functions accessing global variables and object data where locking is necessary.
Definition: AutoVLock.h:80
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
the base class for all data to be used as private data of Qore objects
Definition: AbstractPrivateData.h:44
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:54
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
DLLEXPORT const char * getFirstKey() const
returns the cstring value of the first key in the hash
uint64_t q_rt_flags_t
runtime code execution flags
Definition: common.h:263
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
DLLEXPORT void del()
manually releases the lock currently held
DLLLOCAL void set(QoreVarRWLock *n_rwl)
sets the current lock
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
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack...
Definition: QoreThreadLock.h:128
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
defines a Qore-language class
Definition: QoreClass.h:239
const qore_type_t NT_HASH
type value for QoreHashNode
Definition: node_types.h:51
DLLLOCAL void clear()
leaves the lock locked and the object referenced and clears the object and lock pointers ...
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
DLLLOCAL QoreObject * getObject() const
gets the current object
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:46
reverse constant iterator class for QoreHashNode, to be only created on the stack ...
Definition: QoreHashNode.h:640
DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count and calls derefImpl() if there_can_be_only_one is false, otherwise does nothing
DLLLOCAL void ref()
increments the reference count of the object
Definition: AbstractPrivateData.h:53
DLLEXPORT const char * getLastKey() const
returns the cstring value of the last key in the hash
DLLLOCAL QoreVarRWLock * getRWL() const
gets the current read-write lock
constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:563
a method in a QoreClass
Definition: QoreClass.h:125
DLLEXPORT const char * getName() const
returns the class name