};
struct notification_client {
+ notification_client_id id;
int socket;
/* Client protocol version. */
uint8_t major, minor;
*/
struct cds_list_head condition_list;
struct cds_lfht_node client_socket_ht_node;
+ struct cds_lfht_node client_id_ht_node;
struct {
struct {
/*
static
-int match_client(struct cds_lfht_node *node, const void *key)
+int match_client_socket(struct cds_lfht_node *node, const void *key)
{
/* This double-cast is intended to supress pointer-to-cast warning. */
- int socket = (int) (intptr_t) key;
- struct notification_client *client;
+ const int socket = (int) (intptr_t) key;
+ const struct notification_client *client = caa_container_of(node,
+ struct notification_client, client_socket_ht_node);
- client = caa_container_of(node, struct notification_client,
- client_socket_ht_node);
+ return client->socket == socket;
+}
+
+static
+int match_client_id(struct cds_lfht_node *node, const void *key)
+{
+ /* This double-cast is intended to supress pointer-to-cast warning. */
+ const notification_client_id id = *((notification_client_id *) key);
+ const struct notification_client *client = caa_container_of(
+ node, struct notification_client, client_id_ht_node);
- return !!(client->socket == socket);
+ return client->id == id;
}
static
return key_hash ^ domain_hash;
}
+static
+unsigned long hash_client_socket(int socket)
+{
+ return hash_key_ulong((void *) (unsigned long) socket, lttng_ht_seed);
+}
+
+static
+unsigned long hash_client_id(notification_client_id id)
+{
+ return hash_key_u64(&id, lttng_ht_seed);
+}
+
/*
* Get the type of object to which a given condition applies. Bindings let
* the notification system evaluate a trigger's condition when a given
if (client->socket >= 0) {
(void) lttcomm_close_unix_sock(client->socket);
+ client->socket = -1;
}
lttng_dynamic_buffer_reset(&client->communication.inbound.buffer);
lttng_dynamic_buffer_reset(&client->communication.outbound.buffer);
struct notification_client *client = NULL;
cds_lfht_lookup(state->client_socket_ht,
- hash_key_ulong((void *) (unsigned long) socket, lttng_ht_seed),
- match_client,
+ hash_client_socket(socket),
+ match_client_socket,
(void *) (unsigned long) socket,
&iter);
node = cds_lfht_iter_get_node(&iter);
return client;
}
+/*
+ * Call with rcu_read_lock held (and hold for the lifetime of the returned
+ * client pointer).
+ */
+static
+struct notification_client *get_client_from_id(notification_client_id id,
+ struct notification_thread_state *state)
+{
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *node;
+ struct notification_client *client = NULL;
+
+ cds_lfht_lookup(state->client_id_ht,
+ hash_client_id(id),
+ match_client_id,
+ &id,
+ &iter);
+ node = cds_lfht_iter_get_node(&iter);
+ if (!node) {
+ goto end;
+ }
+
+ client = caa_container_of(node, struct notification_client,
+ client_id_ht_node);
+end:
+ return client;
+}
+
static
bool buffer_usage_condition_applies_to_channel(
const struct lttng_condition *condition,
return -1;
}
-static
-unsigned long hash_client_socket(int socket)
-{
- return hash_key_ulong((void *) (unsigned long) socket, lttng_ht_seed);
-}
-
static
int socket_set_non_blocking(int socket)
{
ret = -1;
goto error;
}
+ client->id = state->next_notification_client_id++;
CDS_INIT_LIST_HEAD(&client->condition_list);
lttng_dynamic_buffer_init(&client->communication.inbound.buffer);
lttng_dynamic_buffer_init(&client->communication.outbound.buffer);
cds_lfht_add(state->client_socket_ht,
hash_client_socket(client->socket),
&client->client_socket_ht_node);
+ cds_lfht_add(state->client_id_ht,
+ hash_client_id(client->id),
+ &client->client_id_ht_node);
rcu_read_unlock();
return ret;
}
cds_lfht_del(state->client_socket_ht,
&client->client_socket_ht_node);
+ cds_lfht_del(state->client_id_ht,
+ &client->client_id_ht_node);
notification_client_destroy(client, state);
end:
rcu_read_unlock();
#include <semaphore.h>
#include "thread.h"
+
+typedef uint64_t notification_client_id;
+
struct notification_thread_handle {
/*
* Queue of struct notification command.
* In order to speed-up and simplify queries, hash tables providing the
* following associations are maintained:
*
- * - client_socket_ht: associate a client's socket (fd) to its "struct client"
- * This hash table owns the "struct client" which must thus be
- * disposed-of on removal from the hash table.
+ * - client_socket_ht: associate a client's socket (fd) to its
+ * "struct notification_client".
+ * This hash table owns the "struct notification_client" which must
+ * thus be disposed-of on removal from the hash table.
+ *
+ * - client_id_ht: associate a client's id to its "struct notification_client"
+ * This hash table holds a _weak_ reference to the
+ * "struct notification_client".
*
* - channel_triggers_ht:
* associates a channel key to a list of
* 7) Session rotation completed
*
* 8) Connection of a client
- * - add client socket to the client_socket_ht.
+ * - add client socket to the client_socket_ht,
+ * - add client socket to the client_id_ht.
*
* 9) Disconnection of a client
+ * - remove client socket from the client_id_ht,
* - remove client socket from the client_socket_ht,
* - traverse all conditions to which the client is subscribed and remove
* the client from the notification_trigger_clients_ht.
int notification_channel_socket;
struct lttng_poll_event events;
struct cds_lfht *client_socket_ht;
+ struct cds_lfht *client_id_ht;
struct cds_lfht *channel_triggers_ht;
struct cds_lfht *session_triggers_ht;
struct cds_lfht *channel_state_ht;
struct cds_lfht *channels_ht;
struct cds_lfht *sessions_ht;
struct cds_lfht *triggers_ht;
+ notification_client_id next_notification_client_id;
};
/* notification_thread_data takes ownership of the channel monitor pipes. */