aboutsummaryrefslogtreecommitdiffstats
path: root/utils.c
diff options
context:
space:
mode:
authorrizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b>2006-04-12 20:40:46 +0000
committerrizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b>2006-04-12 20:40:46 +0000
commit08c77ea86d932596542a63a1a67cb3e6a1229135 (patch)
tree0b296463204ccd97d57e585d6659dd75d15280fc /utils.c
parentdb922028c05355324c33e3a08ce427ed0a16b45f (diff)
add 'show threads' and 'show profile' commands.
These are momstly debugging tools for developers, a bit documented in the header files (utils.h), although more documentation is definitely necessary. The performance impact is close to zero(*) so there is no need to compile it conditionally. (*) not completely true - thread destruction still needs to search a list _but_ this can be easily optimized if we end up with hundreds of active threads (in which case, though, the problem is clearly elsewhere). git-svn-id: http://svn.digium.com/svn/asterisk/trunk@19544 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'utils.c')
-rw-r--r--utils.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/utils.c b/utils.c
index ae4023538..3bd3623d3 100644
--- a/utils.c
+++ b/utils.c
@@ -509,8 +509,42 @@ int ast_utils_init(void)
#undef pthread_create /* For ast_pthread_create function only */
#endif /* !__linux__ */
-int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize)
+/*
+ * support for 'show threads'. The start routine is wrapped by
+ * dummy_start(), so that ast_register_thread() and
+ * ast_unregister_thread() know the thread identifier.
+ */
+struct thr_arg {
+ void *(*start_routine)(void *);
+ void *data;
+ char *name;
+};
+
+/*
+ * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop()
+ * are odd macros which start and end a block, so they _must_ be
+ * used in pairs (the latter with a '1' argument to call the
+ * handler on exit.
+ * On BSD we don't need this, but we keep it for compatibility with the MAC.
+ */
+static void *dummy_start(void *data)
{
+ void *ret;
+ struct thr_arg a = *((struct thr_arg *)data); /* make a local copy */
+
+ free(data);
+ ast_register_thread(a.name);
+ pthread_cleanup_push(ast_unregister_thread, (void *)pthread_self()); /* on unregister */
+ ret = a.start_routine(a.data);
+ pthread_cleanup_pop(1);
+ return ret;
+}
+
+int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize,
+ const char *file, const char *caller, int line, const char *start_fn)
+{
+ struct thr_arg *a;
+
pthread_attr_t lattr;
if (!attr) {
pthread_attr_init(&lattr);
@@ -534,6 +568,17 @@ int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*st
errno = pthread_attr_setstacksize(attr, stacksize);
if (errno)
ast_log(LOG_WARNING, "pthread_attr_setstacksize returned non-zero: %s\n", strerror(errno));
+ a = ast_malloc(sizeof(*a));
+ if (!a)
+ ast_log(LOG_WARNING, "no memory, thread %s will not be listed\n", start_fn);
+ else { /* remap parameters */
+ a->start_routine = start_routine;
+ a->data = data;
+ start_routine = dummy_start;
+ asprintf(&a->name, "%-20s started at [%5d] %s %s()",
+ start_fn, line, file, caller);
+ data = a;
+ }
return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
}