Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugene Tarassov2013-11-26 15:25:57 -0500
committerEugene Tarassov2013-11-26 15:25:57 -0500
commit8ab1b17c06ac3a887e7a41ac4619a54deed9953e (patch)
tree13073bb48cf8f29eeab983db50e6ec316532eae8
parentd68585ef154da0d854d29bb20239bbd6dd5c6408 (diff)
downloadorg.eclipse.tcf.agent-8ab1b17c06ac3a887e7a41ac4619a54deed9953e.tar.gz
org.eclipse.tcf.agent-8ab1b17c06ac3a887e7a41ac4619a54deed9953e.tar.xz
org.eclipse.tcf.agent-8ab1b17c06ac3a887e7a41ac4619a54deed9953e.zip
TCF Agent: channel API is expended to support diagnostic of incorrect usages of channel_lock/channel_unlock functions
-rw-r--r--agent/tcf/framework/cache.c5
-rw-r--r--agent/tcf/framework/channel.c112
-rw-r--r--agent/tcf/framework/channel.h21
-rw-r--r--agent/tcf/framework/channel_pipe.c1
-rw-r--r--agent/tcf/framework/channel_tcp.c1
-rw-r--r--agent/tcf/services/disassembly.c4
-rw-r--r--agent/tcf/services/discovery.c4
-rw-r--r--agent/tcf/services/expressions.c4
-rw-r--r--agent/tcf/services/memoryservice.c8
-rw-r--r--agent/tcf/services/runctrl.c16
10 files changed, 149 insertions, 27 deletions
diff --git a/agent/tcf/framework/cache.c b/agent/tcf/framework/cache.c
index c12f6d56..80d98c72 100644
--- a/agent/tcf/framework/cache.c
+++ b/agent/tcf/framework/cache.c
@@ -49,6 +49,7 @@ static unsigned wait_list_max;
static unsigned id_cnt = 0;
static LINK cache_list = TCF_LIST_INIT(cache_list);
static Channel * def_channel = NULL;
+static const char * channel_lock_msg = "Cache client lock";
#define link_all2cache(x) ((AbstractCache *)((char *)(x) - offsetof(AbstractCache, link)))
@@ -155,7 +156,7 @@ void cache_wait_dbg(const char * file, int line, AbstractCache * cache) {
}
#endif
if (cache->wait_list_cnt == 0) list_add_last(&cache->link, &cache_list);
- if (current_client.channel != NULL) channel_lock(current_client.channel);
+ if (current_client.channel != NULL) channel_lock_with_msg(current_client.channel, channel_lock_msg);
cache->wait_list_buf[cache->wait_list_cnt++] = current_client;
}
#ifndef NDEBUG
@@ -183,7 +184,7 @@ void cache_notify(AbstractCache * cache) {
for (i = 0; i < cnt; i++) {
current_client = wait_list_buf[i];
run_cache_client();
- if (wait_list_buf[i].channel != NULL) channel_unlock(wait_list_buf[i].channel);
+ if (wait_list_buf[i].channel != NULL) channel_unlock_with_msg(wait_list_buf[i].channel, channel_lock_msg);
}
}
diff --git a/agent/tcf/framework/channel.c b/agent/tcf/framework/channel.c
index 5c8c165e..61c43c7c 100644
--- a/agent/tcf/framework/channel.c
+++ b/agent/tcf/framework/channel.c
@@ -47,6 +47,12 @@
# define DEFAULT_SERVER_NAME "TCF Agent"
#endif
+typedef struct ChannelLock {
+ LINK link;
+ const char * msg;
+ unsigned cnt;
+} ChannelLock;
+
static void trigger_channel_shutdown(ShutdownInfo * obj);
ShutdownInfo channel_shutdown = { trigger_channel_shutdown };
@@ -58,15 +64,19 @@ LINK channel_server_root = TCF_LIST_INIT(channel_server_root);
#define out2bcast(A) ((TCFBroadcastGroup *)((char *)(A) - offsetof(TCFBroadcastGroup, out)))
#define bclink2channel(A) ((Channel *)((char *)(A) - offsetof(Channel, bclink)))
#define susplink2channel(A) ((Channel *)((char *)(A) - offsetof(Channel, susplink)))
+#define chan2lock(A) ((ChannelLock *)((char *)(A) - offsetof(ChannelLock, link)))
-static ChannelCreateListener create_listeners[16];
-static int create_listeners_cnt = 0;
+static ChannelCreateListener * create_listeners = NULL;
+static unsigned create_listeners_cnt = 0;
+static unsigned create_listeners_max = 0;
-static ChannelOpenListener open_listeners[16];
-static int open_listeners_cnt = 0;
+static ChannelOpenListener * open_listeners = NULL;
+static unsigned open_listeners_cnt = 0;
+static unsigned open_listeners_max = 0;
-static ChannelCloseListener close_listeners[16];
-static int close_listeners_cnt = 0;
+static ChannelCloseListener * close_listeners = NULL;
+static unsigned close_listeners_cnt = 0;
+static unsigned close_listeners_max = 0;
static const int BROADCAST_OK_STATES = (1 << ChannelStateConnected) | (1 << ChannelStateRedirectSent) | (1 << ChannelStateRedirectReceived);
#define isBoardcastOkay(c) ((1 << (c)->state) & BROADCAST_OK_STATES)
@@ -148,36 +158,45 @@ static ssize_t splice_block_all(OutputStream * out, int fd, size_t size, int64_t
}
void add_channel_create_listener(ChannelCreateListener listener) {
- assert(create_listeners_cnt < (int)(sizeof(create_listeners) / sizeof(ChannelCreateListener)));
+ if (create_listeners_cnt >= create_listeners_max) {
+ create_listeners_max += 8;
+ create_listeners = (ChannelCreateListener *)loc_realloc(create_listeners, sizeof(ChannelCreateListener) * create_listeners_max);
+ }
create_listeners[create_listeners_cnt++] = listener;
}
void add_channel_open_listener(ChannelOpenListener listener) {
- assert(open_listeners_cnt < (int)(sizeof(open_listeners) / sizeof(ChannelOpenListener)));
+ if (open_listeners_cnt >= open_listeners_max) {
+ open_listeners_max += 8;
+ open_listeners = (ChannelOpenListener *)loc_realloc(open_listeners, sizeof(ChannelOpenListener) * open_listeners_max);
+ }
open_listeners[open_listeners_cnt++] = listener;
}
void add_channel_close_listener(ChannelCloseListener listener) {
- assert(close_listeners_cnt < (int)(sizeof(close_listeners) / sizeof(ChannelCloseListener)));
+ if (close_listeners_cnt >= close_listeners_max) {
+ close_listeners_max += 8;
+ close_listeners = (ChannelCloseListener *)loc_realloc(close_listeners, sizeof(ChannelCloseListener) * close_listeners_max);
+ }
close_listeners[close_listeners_cnt++] = listener;
}
void notify_channel_created(Channel * c) {
- int i;
+ unsigned i;
for (i = 0; i < create_listeners_cnt; i++) {
create_listeners[i](c);
}
}
void notify_channel_opened(Channel * c) {
- int i;
+ unsigned i;
for (i = 0; i < open_listeners_cnt; i++) {
open_listeners[i](c);
}
}
void notify_channel_closed(Channel * c) {
- int i;
+ unsigned i;
for (i = 0; i < close_listeners_cnt; i++) {
close_listeners[i](c);
}
@@ -232,6 +251,75 @@ void channel_unlock(Channel * c) {
c->unlock(c);
}
+void channel_lock_with_msg(Channel * c, const char * msg) {
+ c->lock(c);
+#ifndef NDEBUG
+ if (msg != NULL) {
+ int ok = 0;
+ ChannelLock * l = NULL;
+ if (c->locks.next != NULL) {
+ LINK * p;
+ for (p = c->locks.next; p != &c->locks; p = p->next) {
+ l = chan2lock(p);
+ if (l->msg == msg) {
+ l->cnt++;
+ ok = 1;
+ break;
+ }
+ }
+ }
+ else {
+ list_init(&c->locks);
+ }
+ if (!ok) {
+ l = (ChannelLock *)loc_alloc_zero(sizeof(ChannelLock));
+ l->msg = msg;
+ l->cnt = 1;
+ list_add_first(&l->link, &c->locks);
+ }
+ }
+#endif
+}
+
+void channel_unlock_with_msg(Channel * c, const char * msg) {
+#ifndef NDEBUG
+ if (msg != NULL) {
+ int ok = 0;
+ ChannelLock * l = NULL;
+ if (c->locks.next != NULL) {
+ LINK * p;
+ for (p = c->locks.next; p != &c->locks; p = p->next) {
+ l = chan2lock(p);
+ if (l->msg == msg) {
+ l->cnt--;
+ ok = 1;
+ break;
+ }
+ }
+ }
+ if (!ok) {
+ trace(LOG_ALWAYS, "Invalid channel unlock: %s", msg);
+ }
+ else if (l->cnt == 0) {
+ list_remove(&l->link);
+ loc_free(l);
+ }
+ }
+#endif
+ c->unlock(c);
+}
+
+void check_channel_locks(Channel * c) {
+#ifndef NDEBUG
+ if (c->locks.next != NULL) {
+ LINK * p;
+ for (p = c->locks.next; p != &c->locks; p = p->next) {
+ trace(LOG_ALWAYS, "Invalid channel lock: %s", chan2lock(p)->msg);
+ }
+ }
+#endif
+}
+
int is_channel_closed(Channel * c) {
return c->is_closed(c);
}
diff --git a/agent/tcf/framework/channel.h b/agent/tcf/framework/channel.h
index cecf73b4..ae1f9703 100644
--- a/agent/tcf/framework/channel.h
+++ b/agent/tcf/framework/channel.h
@@ -67,6 +67,7 @@ struct Channel {
LINK chanlink; /* Channel list */
LINK bclink; /* Broadcast list */
LINK susplink; /* Suspend list */
+ LINK locks; /* List of channel locks */
int congestion_level; /* Congestion level */
int state; /* Current state */
int disable_zero_copy; /* Don't send ZeroCopy in Hello message even if we support it */
@@ -195,11 +196,29 @@ extern void channel_lock(Channel *);
/*
* Unlock a channel.
* Each call of this function decrements the channel reference counter.
- * If channel is closed and reference count is zero, then the channel object is deallocated.
+ * If channel is closed and reference count is zero, then the channel object is closed.
*/
extern void channel_unlock(Channel *);
/*
+ * Lock a channel. Same as channel_lock(), but, if given a message (e.g. a service name),
+ * it will log a warning if the channel is not unlocked after it is closed.
+ * Note: same char pointer must be used for matching channel_unlock_with_msg() call.
+ */
+extern void channel_lock_with_msg(Channel *, const char *);
+
+/*
+ * Unlock a channel. To be used together with channel_lock_with_msg().
+ */
+extern void channel_unlock_with_msg(Channel *, const char *);
+
+/*
+ * Check for leaked channel locks. The function is called by
+ * channel implementation after the channel is disconnected.
+ */
+extern void check_channel_locks(Channel *);
+
+/*
* Return 1 if channel is closed, otherwise return 0.
*/
extern int is_channel_closed(Channel *);
diff --git a/agent/tcf/framework/channel_pipe.c b/agent/tcf/framework/channel_pipe.c
index dad5bf8d..94d571bb 100644
--- a/agent/tcf/framework/channel_pipe.c
+++ b/agent/tcf/framework/channel_pipe.c
@@ -431,6 +431,7 @@ static void pipe_read_done(void * x) {
pipe_post_read(&c->ibuf, c->obuf, sizeof(c->obuf));
}
else {
+ check_channel_locks(&c->chan);
pipe_unlock(&c->chan);
}
}
diff --git a/agent/tcf/framework/channel_tcp.c b/agent/tcf/framework/channel_tcp.c
index c89c025d..8f1ea8fc 100644
--- a/agent/tcf/framework/channel_tcp.c
+++ b/agent/tcf/framework/channel_tcp.c
@@ -792,6 +792,7 @@ static void tcp_channel_read_done(void * x) {
tcp_post_read(&c->ibuf, c->obuf, sizeof(c->obuf));
}
else {
+ check_channel_locks(&c->chan);
tcp_unlock(&c->chan);
}
}
diff --git a/agent/tcf/services/disassembly.c b/agent/tcf/services/disassembly.c
index ee4f0bbe..297f206a 100644
--- a/agent/tcf/services/disassembly.c
+++ b/agent/tcf/services/disassembly.c
@@ -407,7 +407,7 @@ static void safe_event_disassemble(void * x) {
if (!is_channel_closed(args->c)) {
cache_enter(disassemble_cache_client, args->c, args, sizeof(DisassembleCmdArgs));
}
- channel_unlock(args->c);
+ channel_unlock_with_msg(args->c, DISASSEMBLY);
loc_free(args);
}
#endif
@@ -463,7 +463,7 @@ static void command_disassemble(char * token, Channel * c) {
loc_free(args);
}
else {
- channel_lock(c);
+ channel_lock_with_msg(c, DISASSEMBLY);
post_safe_event(ctx, safe_event_disassemble, args);
}
}
diff --git a/agent/tcf/services/discovery.c b/agent/tcf/services/discovery.c
index 9adc69aa..5a11ce58 100644
--- a/agent/tcf/services/discovery.c
+++ b/agent/tcf/services/discovery.c
@@ -94,7 +94,7 @@ static void connect_done(void * args, int error, Channel * c2) {
else if (!error) {
channel_close(c2);
}
- channel_unlock(c1);
+ channel_unlock_with_msg(c1, LOCATOR);
loc_free(info);
}
@@ -122,7 +122,7 @@ static void command_redirect(char * token, Channel * c) {
if (ps != NULL) {
RedirectInfo * info = (RedirectInfo *)loc_alloc_zero(sizeof(RedirectInfo));
- channel_lock(c);
+ channel_lock_with_msg(c, LOCATOR);
c->state = ChannelStateRedirectReceived;
info->channel = c;
strlcpy(info->token, token, sizeof(info->token));
diff --git a/agent/tcf/services/expressions.c b/agent/tcf/services/expressions.c
index 4f420a90..9ea568e8 100644
--- a/agent/tcf/services/expressions.c
+++ b/agent/tcf/services/expressions.c
@@ -3286,7 +3286,7 @@ static LINK cmd_queue;
static void command_start(CacheClient * client, Channel * channel, void * args, size_t args_size) {
PendingCommand * cmd = (PendingCommand *)loc_alloc_zero(sizeof(PendingCommand));
assert(args_size <= sizeof(cmd->args));
- channel_lock(cmd->channel = channel);
+ channel_lock_with_msg(cmd->channel = channel, EXPRESSIONS);
memcpy(cmd->args, args, args_size);
cmd->args_size = args_size;
cmd->client = client;
@@ -3310,7 +3310,7 @@ static void command_done(void) {
pending_cmd = NULL;
assert(cmd != NULL);
assert(&cmd->link == cmd_queue.next);
- channel_unlock(cmd->channel);
+ channel_unlock_with_msg(cmd->channel, EXPRESSIONS);
list_remove(cmd_queue.next);
loc_free(cmd);
if (list_is_empty(&cmd_queue)) return;
diff --git a/agent/tcf/services/memoryservice.c b/agent/tcf/services/memoryservice.c
index 67eeb500..a8dc1d17 100644
--- a/agent/tcf/services/memoryservice.c
+++ b/agent/tcf/services/memoryservice.c
@@ -359,7 +359,7 @@ static MemoryCommandArgs * read_command_args(char * token, Channel * c, int cmd)
*args = buf;
args->c = c;
strlcpy(args->token, token, sizeof(args->token));
- channel_lock(c);
+ channel_lock_with_msg(c, MEMORY);
context_lock(buf.ctx);
return args;
}
@@ -485,7 +485,7 @@ static void safe_memory_set(void * parm) {
else {
loc_free(args->buf);
}
- channel_unlock(c);
+ channel_unlock_with_msg(c, MEMORY);
context_unlock(ctx);
loc_free(args);
}
@@ -589,7 +589,7 @@ static void safe_memory_get(void * parm) {
else {
loc_free(args->buf);
}
- channel_unlock(c);
+ channel_unlock_with_msg(c, MEMORY);
context_unlock(ctx);
loc_free(args);
}
@@ -677,7 +677,7 @@ static void safe_memory_fill(void * parm) {
else {
loc_free(args->buf);
}
- channel_unlock(c);
+ channel_unlock_with_msg(c, MEMORY);
context_unlock(ctx);
loc_free(args);
}
diff --git a/agent/tcf/services/runctrl.c b/agent/tcf/services/runctrl.c
index e82dd336..bb63cb6f 100644
--- a/agent/tcf/services/runctrl.c
+++ b/agent/tcf/services/runctrl.c
@@ -746,7 +746,7 @@ static void cancel_step_mode(Context * ctx) {
ContextExtensionRC * ext = EXT(ctx);
if (ext->step_channel) {
- channel_unlock(ext->step_channel);
+ channel_unlock_with_msg(ext->step_channel, RUN_CONTROL);
ext->step_channel = NULL;
}
if (ext->step_bp_info != NULL) {
@@ -777,9 +777,11 @@ static void start_step_mode(Context * ctx, Channel * c, int mode, ContextAddress
ext->step_error = NULL;
}
assert(ext->step_channel == NULL);
+ if (ext->step_mode == RM_RESUME || ext->step_mode == RM_REVERSE_RESUME ||
+ ext->step_mode == RM_TERMINATE || ext->step_mode == RM_DETACH) c = NULL;
if (c != NULL) {
ext->step_channel = c;
- channel_lock(ext->step_channel);
+ channel_lock_with_msg(ext->step_channel, RUN_CONTROL);
}
ext->step_done = NULL;
ext->step_mode = mode;
@@ -2258,6 +2260,15 @@ static void event_context_exited(Context * ctx, void * args) {
if (ext->pending_safe_event) check_safe_events(ctx);
}
+static void channel_closed(Channel * c) {
+ LINK * l;
+ for (l = context_root.next; l != &context_root; l = l ->next) {
+ Context * ctx = ctxl2ctxp(l);
+ ContextExtensionRC * ext = EXT(ctx);
+ if (ext->step_channel == c) cancel_step_mode(ctx);
+ }
+}
+
static void event_context_disposed(Context * ctx, void * args) {
cancel_step_mode(ctx);
}
@@ -2292,6 +2303,7 @@ void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg) {
};
broadcast_group = bcg;
add_context_event_listener(&listener, NULL);
+ add_channel_close_listener(channel_closed);
context_extension_offset = context_extension(sizeof(ContextExtensionRC));
add_command_handler(proto, RUN_CONTROL, "getContext", command_get_context);
add_command_handler(proto, RUN_CONTROL, "getChildren", command_get_children);

Back to the top