]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/duktape-1.8.0/src-separate/duk_bi_thread.c
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / third_party / duktape-1.8.0 / src-separate / duk_bi_thread.c
diff --git a/ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/duktape-1.8.0/src-separate/duk_bi_thread.c b/ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/duktape-1.8.0/src-separate/duk_bi_thread.c
new file mode 100644 (file)
index 0000000..813c8a1
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ *  Thread builtins
+ */
+
+#include "duk_internal.h"
+
+/*
+ *  Constructor
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
+       duk_hthread *new_thr;
+       duk_hobject *func;
+
+       /* XXX: need a duk_require_func_or_lfunc_coerce() */
+       if (!duk_is_callable(ctx, 0)) {
+               return DUK_RET_TYPE_ERROR;
+       }
+       func = duk_require_hobject_or_lfunc_coerce(ctx, 0);
+       DUK_ASSERT(func != NULL);
+
+       duk_push_thread(ctx);
+       new_thr = (duk_hthread *) duk_get_hobject(ctx, -1);
+       DUK_ASSERT(new_thr != NULL);
+       new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
+
+       /* push initial function call to new thread stack; this is
+        * picked up by resume().
+        */
+       duk_push_hobject((duk_context *) new_thr, func);
+
+       return 1;  /* return thread */
+}
+
+/*
+ *  Resume a thread.
+ *
+ *  The thread must be in resumable state, either (a) new thread which hasn't
+ *  yet started, or (b) a thread which has previously yielded.  This method
+ *  must be called from an Ecmascript function.
+ *
+ *  Args:
+ *    - thread
+ *    - value
+ *    - isError (defaults to false)
+ *
+ *  Note: yield and resume handling is currently asymmetric.
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_hthread *thr_resume;
+       duk_tval *tv;
+       duk_hobject *func;
+       duk_hobject *caller_func;
+       duk_small_int_t is_error;
+
+       DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
+                            (duk_tval *) duk_get_tval(ctx, 0),
+                            (duk_tval *) duk_get_tval(ctx, 1),
+                            (duk_tval *) duk_get_tval(ctx, 2)));
+
+       DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+       DUK_ASSERT(thr->heap->curr_thread == thr);
+
+       thr_resume = duk_require_hthread(ctx, 0);
+       is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
+       duk_set_top(ctx, 2);
+
+       /* [ thread value ] */
+
+       /*
+        *  Thread state and calling context checks
+        */
+
+       if (thr->callstack_top < 2) {
+               DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
+               goto state_error;
+       }
+       DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);  /* us */
+       DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
+       DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL);  /* caller */
+
+       caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
+       if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
+               DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
+               goto state_error;
+       }
+
+       /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
+        * like for yield.
+        */
+
+       if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
+           thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
+               DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
+               goto state_error;
+       }
+
+       DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
+                  thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
+
+       /* Further state-dependent pre-checks */
+
+       if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
+               /* no pre-checks now, assume a previous yield() has left things in
+                * tip-top shape (longjmp handler will assert for these).
+                */
+       } else {
+               DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
+
+               if ((thr_resume->callstack_top != 0) ||
+                   (thr_resume->valstack_top - thr_resume->valstack != 1)) {
+                       goto state_invalid_initial;
+               }
+               tv = &thr_resume->valstack_top[-1];
+               DUK_ASSERT(tv >= thr_resume->valstack && tv < thr_resume->valstack_top);
+               if (!DUK_TVAL_IS_OBJECT(tv)) {
+                       goto state_invalid_initial;
+               }
+               func = DUK_TVAL_GET_OBJECT(tv);
+               DUK_ASSERT(func != NULL);
+               if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
+                       /* Note: cannot be a bound function either right now,
+                        * this would be easy to relax though.
+                        */
+                       goto state_invalid_initial;
+               }
+
+       }
+
+       /*
+        *  The error object has been augmented with a traceback and other
+        *  info from its creation point -- usually another thread.  The
+        *  error handler is called here right before throwing, but it also
+        *  runs in the resumer's thread.  It might be nice to get a traceback
+        *  from the resumee but this is not the case now.
+        */
+
+#if defined(DUK_USE_AUGMENT_ERROR_THROW)
+       if (is_error) {
+               DUK_ASSERT_TOP(ctx, 2);  /* value (error) is at stack top */
+               duk_err_augment_error_throw(thr);  /* in resumer's context */
+       }
+#endif
+
+#ifdef DUK_USE_DEBUG
+       if (is_error) {
+               DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
+                                    (duk_tval *) duk_get_tval(ctx, 0),
+                                    (duk_tval *) duk_get_tval(ctx, 1)));
+       } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
+               DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
+                                    (duk_tval *) duk_get_tval(ctx, 0),
+                                    (duk_tval *) duk_get_tval(ctx, 1)));
+       } else {
+               DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
+                                    (duk_tval *) duk_get_tval(ctx, 0),
+                                    (duk_tval *) duk_get_tval(ctx, 1)));
+       }
+#endif
+
+       thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
+
+       /* lj value2: thread */
+       DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
+       DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]);  /* side effects */
+
+       /* lj value1: value */
+       DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
+       DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]);  /* side effects */
+       DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
+
+       thr->heap->lj.iserror = is_error;
+
+       DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* call is from executor, so we know we have a jmpbuf */
+       duk_err_longjmp(thr);  /* execution resumes in bytecode executor */
+       return 0;  /* never here */
+
+ state_invalid_initial:
+       DUK_ERROR_TYPE(thr, "invalid initial thread state/stack");
+       return 0;  /* never here */
+
+ state_error:
+       DUK_ERROR_TYPE(thr, "invalid state");
+       return 0;  /* never here */
+}
+
+/*
+ *  Yield the current thread.
+ *
+ *  The thread must be in yieldable state: it must have a resumer, and there
+ *  must not be any yield-preventing calls (native calls and constructor calls,
+ *  currently) in the thread's call stack (otherwise a resume would not be
+ *  possible later).  This method must be called from an Ecmascript function.
+ *
+ *  Args:
+ *    - value
+ *    - isError (defaults to false)
+ *
+ *  Note: yield and resume handling is currently asymmetric.
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_hobject *caller_func;
+       duk_small_int_t is_error;
+
+       DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
+                            (duk_tval *) duk_get_tval(ctx, 0),
+                            (duk_tval *) duk_get_tval(ctx, 1)));
+
+       DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+       DUK_ASSERT(thr->heap->curr_thread == thr);
+
+       is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
+       duk_set_top(ctx, 1);
+
+       /* [ value ] */
+
+       /*
+        *  Thread state and calling context checks
+        */
+
+       if (!thr->resumer) {
+               DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
+               goto state_error;
+       }
+       DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
+
+       if (thr->callstack_top < 2) {
+               DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
+               goto state_error;
+       }
+       DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);  /* us */
+       DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
+       DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL);  /* caller */
+
+       caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
+       if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
+               DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
+               goto state_error;
+       }
+
+       DUK_ASSERT(thr->callstack_preventcount >= 1);  /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
+       if (thr->callstack_preventcount != 1) {
+               /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
+               DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
+                                  (long) thr->callstack_preventcount));
+               goto state_error;
+       }
+
+       /*
+        *  The error object has been augmented with a traceback and other
+        *  info from its creation point -- usually the current thread.
+        *  The error handler, however, is called right before throwing
+        *  and runs in the yielder's thread.
+        */
+
+#if defined(DUK_USE_AUGMENT_ERROR_THROW)
+       if (is_error) {
+               DUK_ASSERT_TOP(ctx, 1);  /* value (error) is at stack top */
+               duk_err_augment_error_throw(thr);  /* in yielder's context */
+       }
+#endif
+
+#ifdef DUK_USE_DEBUG
+       if (is_error) {
+               DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
+                                    (duk_tval *) duk_get_tval(ctx, 0)));
+       } else {
+               DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
+                                    (duk_tval *) duk_get_tval(ctx, 0)));
+       }
+#endif
+
+       /*
+        *  Process yield
+        *
+        *  After longjmp(), processing continues in bytecode executor longjmp
+        *  handler, which will e.g. update thr->resumer to NULL.
+        */
+
+       thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
+
+       /* lj value1: value */
+       DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
+       DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]);  /* side effects */
+       DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
+
+       thr->heap->lj.iserror = is_error;
+
+       DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* call is from executor, so we know we have a jmpbuf */
+       duk_err_longjmp(thr);  /* execution resumes in bytecode executor */
+       return 0;  /* never here */
+
+ state_error:
+       DUK_ERROR_TYPE(thr, "invalid state");
+       return 0;  /* never here */
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
+       duk_push_current_thread(ctx);
+       return 1;
+}