_tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn, const char *)
_tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn, const char *)
_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_thread_call_depth_reset_from_req: void (struct tevent_req *, const char *)
_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
tevent_abort: void (struct tevent_context *, const char *)
tevent_backend_list: const char **(TALLOC_CTX *)
tevent_thread_call_depth_activate: void (size_t *)
tevent_thread_call_depth_deactivate: void (void)
tevent_thread_call_depth_reset_from_req: void (struct tevent_req *)
+tevent_thread_call_depth_set_callback: void (tevent_call_depth_callback_t, void *)
tevent_thread_call_depth_start: void (struct tevent_req *)
tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
/* New event (and request) will always start with call depth 0. */
- tevent_thread_call_depth_set(0);
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_RESET,
+ NULL,
+ 0,
+ __func__);
if (ev->nesting.level > 0) {
if (ev->nesting.hook_fn) {
*
* Part 1: activation/deactivation
*
+ * void tevent_thread_call_depth_set_callback(f, private_data)
+ * Register a callback that can track 'call depth' and 'request flow'
+ * NULL as a function callback means deactivation.
+ *
* Part 2: Mark the request (and its subrequests) to be tracked
*
* tevent_thread_call_depth_start(struct tevent_req *req)
* @{
*/
+enum tevent_thread_call_depth_cmd {
+ TEVENT_CALL_FLOW_REQ_RESET,
+ TEVENT_CALL_FLOW_REQ_CREATE,
+ TEVENT_CALL_FLOW_REQ_CANCEL,
+ TEVENT_CALL_FLOW_REQ_CLEANUP,
+ TEVENT_CALL_FLOW_REQ_NOTIFY_CB,
+ TEVENT_CALL_FLOW_REQ_QUEUE_ENTER,
+ TEVENT_CALL_FLOW_REQ_QUEUE_TRIGGER,
+ TEVENT_CALL_FLOW_REQ_QUEUE_LEAVE,
+};
+
+typedef void (*tevent_call_depth_callback_t)(
+ void *private_data,
+ enum tevent_thread_call_depth_cmd cmd,
+ struct tevent_req *req,
+ size_t depth,
+ const char *fname);
+
+struct tevent_thread_call_depth_state {
+ tevent_call_depth_callback_t cb;
+ void *cb_private;
+};
+
+extern __thread struct tevent_thread_call_depth_state
+ tevent_thread_call_depth_state_g;
+
+/**
+ * Register callback function for request/subrequest call depth / flow tracking.
+ *
+ * @param[in] f External call depth and flow handling function
+ */
+void tevent_thread_call_depth_set_callback(tevent_call_depth_callback_t f,
+ void *private_data);
+
#ifdef TEVENT_DEPRECATED
void tevent_thread_call_depth_activate(size_t *ptr) _DEPRECATED_;
#endif
/**
- * Set the external variable to the call depth of the request req.
+ * Reset the external call depth to the call depth of the request.
*
- * @param[in] req Request from which the call depth is assigned to ext.
+ * @param[in] req Request from which the call depth is reset.
* variable.
*/
void tevent_thread_call_depth_reset_from_req(struct tevent_req *req);
+void _tevent_thread_call_depth_reset_from_req(struct tevent_req *req,
+ const char *fname);
+
+#define tevent_thread_call_depth_reset_from_req(req) \
+ _tevent_thread_call_depth_reset_from_req(req, __func__)
+
/* @} */
#include "tevent.h"
#include "tevent_internal.h"
+#undef tevent_thread_call_depth_reset_from_req
+
/********************************************************************
* Debug wrapper functions, modeled (with lot's of code copied as is)
* after the ev debug wrapper functions
}
}
-static __thread size_t *tevent_thread_call_depth_ptr = NULL;
+_PRIVATE_ __thread
+struct tevent_thread_call_depth_state tevent_thread_call_depth_state_g;
void tevent_thread_call_depth_activate(size_t *ptr)
{
void tevent_thread_call_depth_reset_from_req(struct tevent_req *req)
{
- if (tevent_thread_call_depth_ptr != NULL) {
- *tevent_thread_call_depth_ptr = req->internal.call_depth;
+ _tevent_thread_call_depth_reset_from_req(req, NULL);
+}
+
+void _tevent_thread_call_depth_reset_from_req(struct tevent_req *req,
+ const char *fname)
+{
+ if (tevent_thread_call_depth_state_g.cb != NULL) {
+ tevent_thread_call_depth_state_g.cb(
+ tevent_thread_call_depth_state_g.cb_private,
+ TEVENT_CALL_FLOW_REQ_RESET,
+ req,
+ req->internal.call_depth,
+ fname);
}
}
-_PRIVATE_ void tevent_thread_call_depth_set(size_t depth)
+void tevent_thread_call_depth_set_callback(tevent_call_depth_callback_t f,
+ void *private_data)
{
- if (tevent_thread_call_depth_ptr != NULL) {
- *tevent_thread_call_depth_ptr = depth;
+ /* In case of deactivation, make sure that call depth is set to 0 */
+ if (tevent_thread_call_depth_state_g.cb != NULL) {
+ tevent_thread_call_depth_state_g.cb(
+ tevent_thread_call_depth_state_g.cb_private,
+ TEVENT_CALL_FLOW_REQ_RESET,
+ NULL,
+ 0,
+ "tevent_thread_call_depth_set_callback");
}
+ tevent_thread_call_depth_state_g = (struct tevent_thread_call_depth_state)
+ {
+ .cb = f,
+ .cb_private = private_data,
+ };
}
bool replay));
#endif
-void tevent_thread_call_depth_set(size_t depth);
+static inline void tevent_thread_call_depth_notify(
+ enum tevent_thread_call_depth_cmd cmd,
+ struct tevent_req *req,
+ size_t depth,
+ const char *fname)
+{
+ if (tevent_thread_call_depth_state_g.cb != NULL) {
+ tevent_thread_call_depth_state_g.cb(
+ tevent_thread_call_depth_state_g.cb_private,
+ cmd,
+ req,
+ depth,
+ fname);
+ }
+}
void tevent_trace_point_callback(struct tevent_context *ev,
enum tevent_trace_point);
}
tevent_trace_queue_callback(q->list->ev, e, TEVENT_EVENT_TRACE_DETACH);
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_QUEUE_LEAVE,
+ q->list->req,
+ q->list->req->internal.call_depth,
+ e->trigger_name);
DLIST_REMOVE(q->list, e);
q->length--;
tevent_trace_queue_callback(ev, q->list,
TEVENT_EVENT_TRACE_BEFORE_HANDLER);
/* Set the call depth of the request coming from the queue. */
- tevent_thread_call_depth_set(q->list->req->internal.call_depth);
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_QUEUE_TRIGGER,
+ q->list->req,
+ q->list->req->internal.call_depth,
+ q->list->trigger_name);
q->list->triggered = true;
q->list->trigger(q->list->req, q->list->private_data);
}
queue->length++;
talloc_set_destructor(e, tevent_queue_entry_destructor);
tevent_trace_queue_callback(ev, e, TEVENT_EVENT_TRACE_ATTACH);
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_QUEUE_ENTER,
+ req,
+ req->internal.call_depth,
+ e->trigger_name);
if (!queue->running) {
return e;
*ppdata = data;
/* Initially, talloc_zero_size() sets internal.call_depth to 0 */
- if (parent != NULL && parent->internal.call_depth > 0) {
+ if (parent != NULL) {
req->internal.call_depth = parent->internal.call_depth + 1;
- tevent_thread_call_depth_set(req->internal.call_depth);
}
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CREATE,
+ req,
+ req->internal.call_depth,
+ func);
return req;
}
}
if (req->async.fn != NULL) {
/* Calling back the parent code, decrement the call depth. */
- tevent_thread_call_depth_set(req->internal.call_depth > 0 ?
- req->internal.call_depth - 1 : 0);
+ size_t new_depth = req->internal.call_depth > 0 ?
+ req->internal.call_depth - 1 : 0;
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_NOTIFY_CB,
+ req,
+ new_depth,
+ req->async.fn_name);
req->async.fn(req);
}
}
static void tevent_req_cleanup(struct tevent_req *req)
{
- if (req->private_cleanup.fn == NULL) {
- return;
- }
-
if (req->private_cleanup.state >= req->internal.state) {
/*
* Don't call the cleanup_function multiple times for the same
return;
}
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CLEANUP,
+ req,
+ req->internal.call_depth,
+ req->private_cleanup.fn_name);
+
+ if (req->private_cleanup.fn == NULL) {
+ return;
+ }
+
req->private_cleanup.state = req->internal.state;
req->private_cleanup.fn(req, req->internal.state);
}
bool _tevent_req_cancel(struct tevent_req *req, const char *location)
{
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CANCEL,
+ req,
+ req->internal.call_depth,
+ req->private_cancel.fn_name);
+
if (req->private_cancel.fn == NULL) {
return false;
}