mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-30 10:11:45 +00:00
Compare commits
2 Commits
203796f3c6
...
6ec5e19d01
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ec5e19d01 | ||
|
|
21fff7f362 |
@@ -158,6 +158,13 @@
|
||||
separated by commas eg. m(1111@default,2222@default,...). Folders can be optionally specified using
|
||||
the syntax: mailbox@context/folder</para>
|
||||
</option>
|
||||
<option name="s">
|
||||
<argument name="seconds" required="true" />
|
||||
<para>Don't record until <replaceable>seconds</replaceable> (can be fractional) have elapsed since MixMonitor was invoked.
|
||||
No audio is written to the recording file during this time. If the call ends before this period,
|
||||
no audio will be saved. This can be useful to avoid recording announcements,
|
||||
ringback tones, or other non-essential early audio.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
<parameter name="command">
|
||||
@@ -396,6 +403,8 @@
|
||||
|
||||
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
|
||||
|
||||
#define MIN_SKIP_SECONDS 1
|
||||
|
||||
static const char * const app = "MixMonitor";
|
||||
|
||||
static const char * const stop_app = "StopMixMonitor";
|
||||
@@ -435,6 +444,9 @@ struct mixmonitor {
|
||||
);
|
||||
int call_priority;
|
||||
|
||||
/* Number of seconds (can be fractional) to skip at the start of recording */
|
||||
double skip_seconds;
|
||||
|
||||
/* FUTURE DEVELOPMENT NOTICE
|
||||
* recipient_list will need locks if we make it editable after the monitor is started */
|
||||
AST_LIST_HEAD_NOLOCK(, vm_recipient) recipient_list;
|
||||
@@ -459,6 +471,7 @@ enum mixmonitor_flags {
|
||||
MUXFLAG_AUTO_DELETE = (1 << 16),
|
||||
MUXFLAG_REAL_CALLERID = (1 << 17),
|
||||
MUXFLAG_INTERLEAVED = (1 << 18),
|
||||
MUXFLAG_SKIP = (1 << 19),
|
||||
};
|
||||
|
||||
enum mixmonitor_args {
|
||||
@@ -472,6 +485,7 @@ enum mixmonitor_args {
|
||||
OPT_ARG_BEEP_INTERVAL,
|
||||
OPT_ARG_DEPRECATED_RWSYNC,
|
||||
OPT_ARG_NO_RWSYNC,
|
||||
OPT_ARG_SKIP,
|
||||
OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
|
||||
};
|
||||
|
||||
@@ -493,6 +507,7 @@ AST_APP_OPTIONS(mixmonitor_opts, {
|
||||
AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
|
||||
AST_APP_OPTION_ARG('S', MUXFLAG_DEPRECATED_RWSYNC, OPT_ARG_DEPRECATED_RWSYNC),
|
||||
AST_APP_OPTION_ARG('n', MUXFLAG_NO_RWSYNC, OPT_ARG_NO_RWSYNC),
|
||||
AST_APP_OPTION_ARG('s', MUXFLAG_SKIP, OPT_ARG_SKIP),
|
||||
});
|
||||
|
||||
struct mixmonitor_ds {
|
||||
@@ -777,6 +792,8 @@ static void *mixmonitor_thread(void *obj)
|
||||
int errflag = 0;
|
||||
struct ast_format *format_slin;
|
||||
|
||||
struct timeval skip_start = ast_tvnow();
|
||||
|
||||
/* Keep callid association before any log messages */
|
||||
if (mixmonitor->callid) {
|
||||
ast_callid_threadassoc_add(mixmonitor->callid);
|
||||
@@ -797,6 +814,11 @@ static void *mixmonitor_thread(void *obj)
|
||||
|
||||
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
|
||||
|
||||
if (mixmonitor->skip_seconds > 0.0) {
|
||||
ast_debug(3, "%s skipping initial %.3f seconds\n",
|
||||
mixmonitor->name, mixmonitor->skip_seconds);
|
||||
}
|
||||
|
||||
/* The audiohook must enter and exit the loop locked */
|
||||
ast_audiohook_lock(&mixmonitor->audiohook);
|
||||
while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
|
||||
@@ -822,6 +844,22 @@ static void *mixmonitor_thread(void *obj)
|
||||
|| mixmonitor_autochan_is_bridged(mixmonitor->autochan)) {
|
||||
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
|
||||
|
||||
/* Skip writing audio for the first N seconds */
|
||||
if (mixmonitor->skip_seconds > 0.0) {
|
||||
struct timeval now = ast_tvnow();
|
||||
double elapsed = ast_tvdiff_ms(now, skip_start) / 1000.0;
|
||||
|
||||
if (elapsed < mixmonitor->skip_seconds) {
|
||||
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
|
||||
/* Skip this frame and continue */
|
||||
goto frame_cleanup;
|
||||
} else {
|
||||
ast_debug(3, "%s skip period %.3f seconds elapsed; starting to write audio\n",
|
||||
mixmonitor->name, mixmonitor->skip_seconds);
|
||||
mixmonitor->skip_seconds = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write out the frame(s) */
|
||||
if ((*fs_read) && (fr_read)) {
|
||||
struct ast_frame *cur;
|
||||
@@ -888,6 +926,8 @@ static void *mixmonitor_thread(void *obj)
|
||||
}
|
||||
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
|
||||
}
|
||||
|
||||
frame_cleanup:
|
||||
/* All done! free it. */
|
||||
if (fr) {
|
||||
ast_frame_free(fr, 0);
|
||||
@@ -1043,7 +1083,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
|
||||
unsigned int flags, int readvol, int writevol,
|
||||
const char *post_process, const char *filename_write,
|
||||
char *filename_read, const char *uid_channel_var,
|
||||
const char *recipients, const char *beep_id)
|
||||
const char *recipients, const char *beep_id, double skip_seconds)
|
||||
{
|
||||
pthread_t thread;
|
||||
struct mixmonitor *mixmonitor;
|
||||
@@ -1085,6 +1125,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
|
||||
|
||||
/* Copy over flags and channel name */
|
||||
mixmonitor->flags = flags;
|
||||
mixmonitor->skip_seconds = skip_seconds;
|
||||
if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
|
||||
mixmonitor_free(mixmonitor);
|
||||
return -1;
|
||||
@@ -1241,6 +1282,7 @@ static char *filename_parse(char *filename, char *buffer, size_t len)
|
||||
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
int x, readvol = 0, writevol = 0;
|
||||
double skip_seconds = 0.0;
|
||||
char *filename_read = NULL;
|
||||
char *filename_write = NULL;
|
||||
char filename_buffer[1024] = "";
|
||||
@@ -1340,6 +1382,22 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, MUXFLAG_SKIP)) {
|
||||
if (ast_strlen_zero(opts[OPT_ARG_SKIP])) {
|
||||
ast_log(LOG_WARNING, "No skip value provided for the 's' (skip) option; skipping will be ignored as no default exists.\n");
|
||||
} else {
|
||||
char *endptr = NULL;
|
||||
double val = strtod(opts[OPT_ARG_SKIP], &endptr);
|
||||
if (endptr == opts[OPT_ARG_SKIP] || *endptr != '\0') {
|
||||
ast_log(LOG_WARNING, "Skip value '%s' is not a valid number; ignoring skip.\n", opts[OPT_ARG_SKIP]);
|
||||
} else if (val < (double) MIN_SKIP_SECONDS) {
|
||||
ast_log(LOG_WARNING, "Skip value %.3f is below minimum %d; ignoring skip.\n", val, MIN_SKIP_SECONDS);
|
||||
} else {
|
||||
skip_seconds = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
|
||||
|
||||
@@ -1367,7 +1425,8 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
|
||||
filename_read,
|
||||
uid_channel_var,
|
||||
recipients,
|
||||
beep_id)) {
|
||||
beep_id,
|
||||
skip_seconds)) {
|
||||
ast_module_unref(ast_module_info->self);
|
||||
}
|
||||
|
||||
|
||||
@@ -266,6 +266,8 @@ for i in "${!COREDUMPS[@]}" ; do
|
||||
libdir=$(dirname "${libfile}")
|
||||
}
|
||||
|
||||
[ "$(dirname "${astbin}")" == "." ] && astbin="$(which "${astbin}")" || :
|
||||
astbin=$(realpath -e "${astbin}")
|
||||
msg " ASTBIN: $astbin"
|
||||
msg " MODDIR: $moddir"
|
||||
msg " ETCDIR: $etcdir"
|
||||
@@ -288,7 +290,7 @@ for i in "${!COREDUMPS[@]}" ; do
|
||||
cfname=$(basename "${cf}")
|
||||
|
||||
# Produce all the output files
|
||||
${GDB} -n --batch -q --ex "source $gdbinit" "${astbin}" "$cf" 2>/dev/null | (
|
||||
${GDB} -n --batch -q --iex "source $gdbinit" -ex "dump-asterisk" "${astbin}" "$cf" 2>/dev/null | (
|
||||
of=/dev/null
|
||||
while IFS= read -r line ; do
|
||||
if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
|
||||
@@ -507,7 +509,7 @@ extract_binary_name() {
|
||||
# shellcheck disable=SC2317
|
||||
extract_string_symbol() {
|
||||
${GDB} "$1" "$2" -q --batch \
|
||||
-ex "p $3" 2>/dev/null \
|
||||
-ex "p (char *)$3" 2>/dev/null \
|
||||
| sed -n -r -e 's/[$]1\s*=\s*[0-9a-fx]+\s+<[^>]+>\s+"([^"]+)"/\1/gp'
|
||||
return 0
|
||||
}
|
||||
@@ -771,6 +773,12 @@ def s_strip(value):
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if value.type.code in [ gdb.TYPE_CODE_ARRAY, gdb.TYPE_CODE_PTR ]:
|
||||
return value.string()
|
||||
except:
|
||||
pass
|
||||
|
||||
return str(value).strip('" ') or "<None>"
|
||||
|
||||
|
||||
@@ -898,6 +906,64 @@ def get_container_rbtree_objects(name, type, on_object=None):
|
||||
|
||||
return objs
|
||||
|
||||
def get_container_count(name):
|
||||
return int(gdb.parse_and_eval(name).dereference()['elements'])
|
||||
|
||||
|
||||
def get_container_map_objects(name, type, on_object=None):
|
||||
"""Retrieve a list of objects from a C++ map.
|
||||
|
||||
Expected on_object signature:
|
||||
|
||||
res, stop = on_object(GDB Value)
|
||||
|
||||
The given callback, on_object, is called for each object found in the
|
||||
map. The callback is passed a dereferenced GDB Value object and
|
||||
expects an object to be returned, which is then appended to a list of
|
||||
objects to be returned by this function. Iteration can be stopped by
|
||||
returning "True" for the second return value.
|
||||
|
||||
If on_object is not specified then the dereferenced GDB value is instead
|
||||
added directly to the returned list.
|
||||
|
||||
Args:
|
||||
name: The name of the map
|
||||
type: The type of objects stored in the container
|
||||
on_object: Optional function called on each object found
|
||||
|
||||
Return:
|
||||
A list of map objects
|
||||
"""
|
||||
objs = []
|
||||
map = gdb.parse_and_eval(name)
|
||||
node = map['_M_t']['_M_impl']['_M_header']['_M_left']
|
||||
tree_size = map['_M_t']['_M_impl']['_M_node_count']
|
||||
for i in range(0, tree_size):
|
||||
obj_node = (node + 2)
|
||||
obj_p = obj_node.cast(gdb.lookup_type(type).pointer().pointer()).dereference()
|
||||
obj = obj_p.dereference()
|
||||
res, stop = on_object(obj) if on_object else (obj, False)
|
||||
if res:
|
||||
objs.append(res)
|
||||
if stop:
|
||||
return objs
|
||||
|
||||
if node['_M_right'] != 0:
|
||||
node = node['_M_right']
|
||||
while node['_M_left'] != 0:
|
||||
node = node['_M_left']
|
||||
else:
|
||||
tmp_node = node['_M_parent']
|
||||
while node == tmp_node['_M_right']:
|
||||
node = tmp_node
|
||||
tmp_node = tmp_node['_M_parent']
|
||||
if node['_M_right'] != tmp_node:
|
||||
node = tmp_node
|
||||
return objs
|
||||
|
||||
def get_map_count(name):
|
||||
map = gdb.parse_and_eval(name)
|
||||
return map['_M_t']['_M_impl']['_M_node_count']
|
||||
|
||||
def build_info():
|
||||
|
||||
@@ -969,7 +1035,7 @@ class TaskProcessor(object):
|
||||
def __init__(self, name, processed, in_queue, max_depth,
|
||||
low_water, high_water):
|
||||
|
||||
self.name = s_strip(name)
|
||||
self.name = str(name).strip('"')
|
||||
self.processed = int(processed)
|
||||
self.in_queue = int(in_queue)
|
||||
self.max_depth = int(max_depth)
|
||||
@@ -979,7 +1045,7 @@ class TaskProcessor(object):
|
||||
|
||||
class Channel(object):
|
||||
|
||||
template = ("{name:30} {context:>20} {exten:>20} {priority:>10} {state:>25} "
|
||||
template = ("{name:42} {context:>20} {exten:>20} {priority:>10} {state:>25} "
|
||||
"{app:>20} {data:>30} {caller_id:>15} {created:>30} "
|
||||
"{account_code:>15} {peer_account:>15} {bridge_id:>38}")
|
||||
|
||||
@@ -989,14 +1055,22 @@ class Channel(object):
|
||||
'account_code': 'Accountcode', 'peer_account': 'PeerAccount',
|
||||
'bridge_id': 'BridgeID'}
|
||||
|
||||
container = 'current_channel_storage_instance->handle->handle'
|
||||
map = '(((struct mni_channelstorage_driver_pvt *)current_channel_storage_instance->handle)->by_name)'
|
||||
|
||||
@staticmethod
|
||||
def objects():
|
||||
|
||||
try:
|
||||
objs = get_container_hash_objects('channels',
|
||||
'struct ast_channel', Channel.from_value)
|
||||
|
||||
objs.sort(key=lambda x: x.name.lower())
|
||||
driver = gdb.parse_and_eval("current_channel_storage_driver")
|
||||
driver_name = driver['driver_name'].string()
|
||||
if driver_name == "cpp_map_name_id":
|
||||
objs = get_container_map_objects(Channel.map,
|
||||
'struct ast_channel', Channel.from_value)
|
||||
else:
|
||||
objs = get_container_hash_objects(Channel.container,
|
||||
'struct ast_channel', Channel.from_value)
|
||||
objs.sort(key=lambda x: x.name.lower())
|
||||
except:
|
||||
return []
|
||||
|
||||
@@ -1025,13 +1099,19 @@ class Channel(object):
|
||||
|
||||
@staticmethod
|
||||
def summary():
|
||||
driver = gdb.parse_and_eval("current_channel_storage_driver")
|
||||
driver_name = driver['driver_name'].string()
|
||||
if driver_name == "cpp_map_name_id":
|
||||
count = get_map_count(Channel.map)
|
||||
else:
|
||||
count = get_container_count(Channel.container)
|
||||
|
||||
try:
|
||||
return ("{0} active channels\n"
|
||||
"{1} active calls\n"
|
||||
"{2} calls processed".format(
|
||||
int(gdb.parse_and_eval(
|
||||
'channels').dereference()['elements']),
|
||||
return ("Channel Driver Name: {0}\n"
|
||||
"{1} active channels\n"
|
||||
"{2} active calls\n"
|
||||
"{3} calls processed".format(driver_name,
|
||||
count,
|
||||
get("countcalls"),
|
||||
get("totalcalls")))
|
||||
except:
|
||||
@@ -1197,76 +1277,81 @@ DumpAsteriskCommand ()
|
||||
end
|
||||
|
||||
define show_locks
|
||||
set $n = lock_infos.first
|
||||
set $n = lock_infos.first
|
||||
|
||||
if $argc == 0
|
||||
printf " where_held count-|\n"
|
||||
printf " suspended-| |\n"
|
||||
printf " type- | times locked-| | |\n"
|
||||
printf "thread status file line function lock name | lock addr | | |\n"
|
||||
else
|
||||
printf "thread,status,file,line,function,lock_name,lock_type,lock_addr,times_locked,suspended,where_held_count,where_held_file,where_held_line,where_held_function,there_held_thread\n"
|
||||
end
|
||||
if $argc == 0
|
||||
printf "%s\n", " where_held count-|"
|
||||
printf "%s\n", " suspended-| |"
|
||||
printf "%s\n", " type-| times locked-| | |"
|
||||
printf "%-14s %-36s %6s %-42s %-8s %-36s %3s %-14s %3s %3s %3s\n",\
|
||||
"thread","file","line","function","status","lock name","|","lock addr","|","|","|"
|
||||
printf "%s\n", "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||||
|
||||
while $n
|
||||
if $n->num_locks > 0
|
||||
else
|
||||
printf "thread,status,file,line,function,lock_name,lock_type,lock_addr,times_locked,suspended,where_held_count,where_held_file,where_held_line,where_held_function,there_held_thread\n"
|
||||
end
|
||||
|
||||
while $n
|
||||
if $n->num_locks > 0
|
||||
set $i = 0
|
||||
while $i < $n->num_locks
|
||||
if $n->locks[$i]->suspended == 0
|
||||
if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->tracking
|
||||
if $n->locks[$i]->type > 0
|
||||
set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track
|
||||
else
|
||||
set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
|
||||
end
|
||||
end
|
||||
set $reentrancy = $track->reentrancy
|
||||
set $pending = $n->locks[$i]->pending
|
||||
if $argc > 0
|
||||
printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\
|
||||
$n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
|
||||
$n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
|
||||
$n->locks[$i]->suspended, $track->reentrancy
|
||||
if $reentrancy
|
||||
if $pending
|
||||
printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0]
|
||||
end
|
||||
end
|
||||
if $n->locks[$i]->suspended != 47
|
||||
if $n->locks[$i]->pending > 0
|
||||
set $status = "waiting"
|
||||
end
|
||||
if $n->locks[$i]->pending < 0
|
||||
set $status = "failed"
|
||||
end
|
||||
if $n->locks[$i]->pending == 0
|
||||
set $status = "holding"
|
||||
end
|
||||
|
||||
if $n->locks[$i]->type == 0
|
||||
set $ltype = "M"
|
||||
end
|
||||
if $n->locks[$i]->type == 1
|
||||
set $ltype = "RD"
|
||||
end
|
||||
if $n->locks[$i]->type == 2
|
||||
set $ltype = "WR"
|
||||
end
|
||||
|
||||
if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
|
||||
if $n->locks[$i]->type > 0
|
||||
set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track
|
||||
else
|
||||
if $n->locks[$i]->pending < 0
|
||||
printf "%p failed %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
|
||||
$n->thread_id,\
|
||||
$n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
|
||||
$n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
|
||||
$n->locks[$i]->suspended, $track->reentrancy
|
||||
end
|
||||
if $n->locks[$i]->pending == 0
|
||||
printf "%p holding %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
|
||||
$n->thread_id,\
|
||||
$n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
|
||||
$n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
|
||||
$n->locks[$i]->suspended, $track->reentrancy
|
||||
end
|
||||
if $n->locks[$i]->pending > 0
|
||||
printf "%p waiting %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
|
||||
$n->thread_id,\
|
||||
$n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
|
||||
$n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
|
||||
$n->locks[$i]->suspended, $track->reentrancy
|
||||
end
|
||||
if $reentrancy
|
||||
if $pending
|
||||
printf "\n held at: %-20s %6d %-36s by 0x%08lx", $track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0]
|
||||
end
|
||||
end
|
||||
set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
|
||||
end
|
||||
printf "\n"
|
||||
end
|
||||
set $i = $i + 1
|
||||
end
|
||||
if $track
|
||||
set $reentrancy = $track->reentrancy
|
||||
else
|
||||
set $reentrancy = 0
|
||||
end
|
||||
set $pending = $n->locks[$i]->pending
|
||||
if $argc > 0
|
||||
printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\
|
||||
$n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
|
||||
$n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
|
||||
$n->locks[$i]->suspended, $reentrancy
|
||||
if $reentrancy && $pending
|
||||
printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0]
|
||||
end
|
||||
else
|
||||
printf "%14p %-36s %6d %-42s %-8s %-36s %3s %-14p %3d %3d %3d", \
|
||||
$n->thread_id, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func, $status, \
|
||||
$n->locks[$i]->lock_name, $ltype, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
|
||||
$n->locks[$i]->suspended, $reentrancy
|
||||
if $reentrancy && $pending
|
||||
printf "\n held at: %s:%d %s() by 0x%08lx", \
|
||||
$track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0]
|
||||
end
|
||||
end
|
||||
printf "\n"
|
||||
end
|
||||
set $i = $i + 1
|
||||
end
|
||||
end
|
||||
set $n = $n->entry->next
|
||||
end
|
||||
end
|
||||
|
||||
dump-asterisk
|
||||
|
||||
Reference in New Issue
Block a user