Add jul-app ABI/API and handle registration
authorDavid Goulet <dgoulet@efficios.com>
Tue, 1 Oct 2013 18:22:22 +0000 (14:22 -0400)
committerDavid Goulet <dgoulet@efficios.com>
Wed, 16 Oct 2013 14:24:36 +0000 (10:24 -0400)
Registration is done in the jul thread and the created jul-app are
attached to existing UST app.

At this stage, there is no need for the UST app to be linked to the JUL
app but in the future, by adding new features, this will be needed.

Enable/Disable one or all events are supported. Also, once a JUL
application registers, it's updated with the already enabled events.

Signed-off-by: David Goulet <dgoulet@efficios.com>
12 files changed:
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/event.c
src/bin/lttng-sessiond/event.h
src/bin/lttng-sessiond/jul-thread.c
src/bin/lttng-sessiond/jul.c
src/bin/lttng-sessiond/jul.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/ust-app.h
src/common/defaults.h
src/common/sessiond-comm/Makefile.am
src/common/sessiond-comm/jul.h [new file with mode: 0644]

index 6709926572c00203dbe34242d6ff3367c9b6d077..8051973ded6cdfa184462f42482ef1857454e0e4 100644 (file)
@@ -1022,6 +1022,19 @@ int cmd_disable_event(struct ltt_session *session, int domain,
                                channel_name);
                break;
        }
+       case LTTNG_DOMAIN_JUL:
+       {
+               struct ltt_ust_session *usess = session->ust_session;
+
+               assert(usess);
+
+               ret = event_jul_disable(usess, event_name);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               break;
+       }
 #if 0
        case LTTNG_DOMAIN_UST_EXEC_NAME:
        case LTTNG_DOMAIN_UST_PID:
@@ -1112,6 +1125,19 @@ int cmd_disable_event_all(struct ltt_session *session, int domain,
 
                DBG3("Disable all UST events in channel %s completed", channel_name);
 
+               break;
+       }
+       case LTTNG_DOMAIN_JUL:
+       {
+               struct ltt_ust_session *usess = session->ust_session;
+
+               assert(usess);
+
+               ret = event_jul_disable_all(usess);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
                break;
        }
 #if 0
@@ -1350,6 +1376,46 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
                }
                break;
        }
+       case LTTNG_DOMAIN_JUL:
+       {
+               struct lttng_event uevent;
+               struct lttng_domain tmp_dom;
+               struct ltt_ust_session *usess = session->ust_session;
+
+               assert(usess);
+
+               /* Create the default JUL tracepoint. */
+               uevent.type = LTTNG_EVENT_TRACEPOINT;
+               uevent.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
+               strncpy(uevent.name, DEFAULT_JUL_EVENT_NAME, sizeof(uevent.name));
+               uevent.name[sizeof(uevent.name) - 1] = '\0';
+
+               /*
+                * The domain type is changed because we are about to enable the
+                * default channel and event for the JUL domain that are hardcoded.
+                * This happens in the UST domain.
+                */
+               memcpy(&tmp_dom, domain, sizeof(tmp_dom));
+               tmp_dom.type = LTTNG_DOMAIN_UST;
+
+               ret = cmd_enable_event(session, &tmp_dom, DEFAULT_JUL_CHANNEL_NAME,
+                               &uevent, NULL, wpipe);
+               if (ret != LTTNG_OK && ret != LTTNG_ERR_UST_EVENT_ENABLED) {
+                       goto error;
+               }
+
+               /* The wild card * means that everything should be enabled. */
+               if (strncmp(event->name, "*", 1) == 0 && strlen(event->name) == 1) {
+                       ret = event_jul_enable_all(usess);
+               } else {
+                       ret = event_jul_enable(usess, event);
+               }
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               break;
+       }
 #if 0
        case LTTNG_DOMAIN_UST_EXEC_NAME:
        case LTTNG_DOMAIN_UST_PID:
@@ -1520,6 +1586,41 @@ int cmd_enable_event_all(struct ltt_session *session,
                        goto error;
                }
 
+               break;
+       }
+       case LTTNG_DOMAIN_JUL:
+       {
+               struct lttng_event uevent;
+               struct lttng_domain tmp_dom;
+               struct ltt_ust_session *usess = session->ust_session;
+
+               assert(usess);
+
+               /* Create the default JUL tracepoint. */
+               uevent.type = LTTNG_EVENT_TRACEPOINT;
+               uevent.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
+               strncpy(uevent.name, DEFAULT_JUL_EVENT_NAME, sizeof(uevent.name));
+               uevent.name[sizeof(uevent.name) - 1] = '\0';
+
+               /*
+                * The domain type is changed because we are about to enable the
+                * default channel and event for the JUL domain that are hardcoded.
+                * This happens in the UST domain.
+                */
+               memcpy(&tmp_dom, domain, sizeof(tmp_dom));
+               tmp_dom.type = LTTNG_DOMAIN_UST;
+
+               ret = cmd_enable_event(session, &tmp_dom, DEFAULT_JUL_CHANNEL_NAME,
+                               &uevent, NULL, wpipe);
+               if (ret != LTTNG_OK && ret != LTTNG_ERR_UST_EVENT_ENABLED) {
+                       goto error;
+               }
+
+               ret = event_jul_enable_all(usess);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
                break;
        }
 #if 0
index 9a8ed63d108696b223876ae0236097bddcd4ec2b..77818e587d4511f65eba47f38f71d5d292cc7f1e 100644 (file)
@@ -607,3 +607,180 @@ error:
        rcu_read_unlock();
        return ret;
 }
+
+/*
+ * Enable all JUL event for a given UST session.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int event_jul_enable_all(struct ltt_ust_session *usess)
+{
+       int ret;
+       struct jul_event *jevent;
+       struct lttng_event event;
+       struct lttng_ht_iter iter;
+
+       assert(usess);
+
+       DBG("Event JUL enabling ALL events for session %" PRIu64, usess->id);
+
+       /* Create the * wildcard event name for the Java agent. */
+       memset(event.name, 0, sizeof(event.name));
+       strncpy(event.name, "*", sizeof(event.name));
+       event.name[sizeof(event.name) - 1] = '\0';
+
+       /* Enable event on JUL application through TCP socket. */
+       ret = event_jul_enable(usess, &event);
+       if (ret != LTTNG_OK) {
+               goto error;
+       }
+
+       /* Flag every event that they are now enabled. */
+       rcu_read_lock();
+       cds_lfht_for_each_entry(usess->domain_jul.events->ht, &iter.iter, jevent,
+                       node.node) {
+               jevent->enabled = 1;
+       }
+       rcu_read_unlock();
+
+       ret = LTTNG_OK;
+
+error:
+       return ret;
+}
+
+/*
+ * Enable a single JUL event for a given UST session.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int event_jul_enable(struct ltt_ust_session *usess, struct lttng_event *event)
+{
+       int ret, created = 0;
+       struct jul_event *jevent;
+
+       assert(usess);
+       assert(event);
+
+       DBG("Event JUL enabling %s for session %" PRIu64, event->name, usess->id);
+
+       jevent = jul_find_by_name(event->name, &usess->domain_jul);
+       if (!jevent) {
+               jevent = jul_create_event(event->name);
+               if (!jevent) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto error;
+               }
+               created = 1;
+       }
+
+       /* Already enabled? */
+       if (jevent->enabled) {
+               goto end;
+       }
+
+       ret = jul_enable_event(jevent);
+       if (ret != LTTNG_OK) {
+               goto error;
+       }
+
+       /* If the event was created prior to the enable, add it to the domain. */
+       if (created) {
+               jul_add_event(jevent, &usess->domain_jul);
+       }
+
+end:
+       return LTTNG_OK;
+
+error:
+       if (created) {
+               jul_destroy_event(jevent);
+       }
+       return ret;
+}
+
+/*
+ * Disable a single JUL event for a given UST session.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int event_jul_disable(struct ltt_ust_session *usess, char *event_name)
+{
+       int ret;
+       struct jul_event *jevent;
+
+       assert(usess);
+       assert(event_name);
+
+       DBG("Event JUL disabling %s for session %" PRIu64, event_name, usess->id);
+
+       jevent = jul_find_by_name(event_name, &usess->domain_jul);
+       if (!jevent) {
+               ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+               goto error;
+       }
+
+       /* Already disabled? */
+       if (!jevent->enabled) {
+               goto end;
+       }
+
+       ret = jul_disable_event(jevent);
+       if (ret != LTTNG_OK) {
+               goto error;
+       }
+
+end:
+       return LTTNG_OK;
+
+error:
+       return ret;
+}
+/*
+ * Disable all JUL event for a given UST session.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int event_jul_disable_all(struct ltt_ust_session *usess)
+{
+       int ret, do_disable = 0;
+       struct jul_event *jevent;
+       struct lttng_ht_iter iter;
+
+       assert(usess);
+
+       /* Enable event on JUL application through TCP socket. */
+       ret = event_jul_disable(usess, "*");
+       if (ret != LTTNG_OK) {
+               if (ret == LTTNG_ERR_UST_EVENT_NOT_FOUND) {
+                       /*
+                        * This means that no enable all was done before but still a user
+                        * could want to disable everything even though the * wild card
+                        * event does not exists.
+                        */
+                       do_disable = 1;
+               } else {
+                       goto error;
+               }
+       }
+
+       /* Flag every event that they are now enabled. */
+       rcu_read_lock();
+       cds_lfht_for_each_entry(usess->domain_jul.events->ht, &iter.iter, jevent,
+                       node.node) {
+               if (jevent->enabled && do_disable) {
+                       ret = event_jul_disable(usess, jevent->name);
+                       if (ret != LTTNG_OK) {
+                               rcu_read_unlock();
+                               goto error;
+                       }
+               }
+               jevent->enabled = 0;
+       }
+       rcu_read_unlock();
+
+       ret = LTTNG_OK;
+
+error:
+       return ret;
+}
index 819111599c15da37b2d75bd0e11ce2f3fcc464bd..1b92a6a7f563e1524f344be40113f99303a27f87 100644 (file)
@@ -45,4 +45,10 @@ int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess,
 int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
 
+int event_jul_enable(struct ltt_ust_session *usess, struct lttng_event *event);
+int event_jul_enable_all(struct ltt_ust_session *usess);
+
+int event_jul_disable(struct ltt_ust_session *usess, char *event_name);
+int event_jul_disable_all(struct ltt_ust_session *usess);
+
 #endif /* _LTT_EVENT_H */
index 9bc82eac7a705e680a812e8757dce083c1caa2b3..972186059dd3f08fa7ab5350fb804936ee16bb12 100644 (file)
@@ -26,6 +26,8 @@
 #include "fd-limit.h"
 #include "jul-thread.h"
 #include "lttng-sessiond.h"
+#include "session.h"
+#include "utils.h"
 
 /*
  * Note that there is not port here. It's set after this URI is parsed so we
  */
 static const char *default_reg_uri = "tcp://localhost";
 
+/*
+ * Update JUL application using the given socket. This is done just after
+ * registration was successful.
+ *
+ * This is a quite heavy call in terms of locking since the session list lock
+ * AND session lock are acquired.
+ */
+static void update_jul_app(int sock)
+{
+       struct ltt_session *session, *stmp;
+       struct ltt_session_list *list;
+
+       list = session_get_list();
+       assert(list);
+
+       session_lock_list();
+       cds_list_for_each_entry_safe(session, stmp, &list->head, list) {
+               session_lock(session);
+               if (session->ust_session) {
+                       jul_update(&session->ust_session->domain_jul, sock);
+               }
+               session_unlock(session);
+       }
+       session_unlock_list();
+}
+
+/*
+ * Destroy a JUL application by socket.
+ */
+static void destroy_jul_app(int sock)
+{
+       struct jul_app *app;
+
+       assert(sock >= 0);
+
+       /*
+        * Not finding an application is a very important error that should NEVER
+        * happen. The hash table deletion is ONLY done through this call even on
+        * thread cleanup.
+        */
+       rcu_read_lock();
+       app = jul_find_app_by_sock(sock);
+       assert(app);
+       rcu_read_unlock();
+
+       /* RCU read side lock is taken in this function call. */
+       jul_delete_app(app);
+
+       /* The application is freed in a RCU call but the socket is closed here. */
+       jul_destroy_app(app);
+}
+
+/*
+ * Cleanup remaining JUL apps in the hash table. This should only be called in
+ * the exit path of the thread.
+ */
+static void clean_jul_apps_ht(void)
+{
+       struct lttng_ht_node_ulong *node;
+       struct lttng_ht_iter iter;
+
+       DBG3("[jul-thread] Cleaning JUL apps ht");
+
+       rcu_read_lock();
+       cds_lfht_for_each_entry(jul_apps_ht_by_sock->ht, &iter.iter, node, node) {
+               struct jul_app *app;
+
+               app = caa_container_of(node, struct jul_app, node);
+               destroy_jul_app(app->sock->fd);
+       }
+       rcu_read_unlock();
+}
+
 /*
  * Create and init socket from uri.
  */
@@ -100,6 +175,71 @@ static void destroy_tcp_socket(struct lttcomm_sock *sock)
        lttcomm_destroy_sock(sock);
 }
 
+/*
+ * Handle a new JUL registration using the reg socket. After that, a new JUL
+ * application is added to the global hash table and attach to an UST app
+ * object.
+ *
+ * Return the new FD created upon accept() on success or else a negative errno
+ * value.
+ */
+static int handle_registration(struct lttcomm_sock *reg_sock)
+{
+       int ret;
+       pid_t pid;
+       ssize_t size;
+       struct jul_app *app;
+       struct jul_register_msg msg;
+       struct lttcomm_sock *new_sock;
+
+       assert(reg_sock);
+
+       new_sock = reg_sock->ops->accept(reg_sock);
+       if (!new_sock) {
+               ret = -ENOTCONN;
+               goto error;
+       }
+
+       size = new_sock->ops->recvmsg(new_sock, &msg, sizeof(msg), 0);
+       if (size < sizeof(msg)) {
+               ret = -errno;
+               goto error_socket;
+       }
+       pid = be32toh(msg.pid);
+
+       DBG2("[jul-thread] New registration for pid %d on socket %d", pid,
+                       new_sock->fd);
+
+       app = jul_create_app(pid, new_sock);
+       if (!app) {
+               ret = -ENOMEM;
+               goto error_socket;
+       }
+
+       /*
+        * Add before assigning the socket value to the UST app so it can be found
+        * concurrently.
+        */
+       jul_add_app(app);
+
+       /*
+        * Attach JUL application to a UST app object if one exists.
+        *
+        * FIXME: This implies that the UST app object exists and created before
+        * JUL registration. Must confirm or else JUL app will leak until socket is
+        * closed by the application.
+        */
+       jul_attach_app(app);
+
+       return new_sock->fd;
+
+error_socket:
+       new_sock->ops->close(new_sock);
+       lttcomm_destroy_sock(new_sock);
+error:
+       return ret;
+}
+
 /*
  * This thread manage application notify communication.
  */
@@ -115,6 +255,9 @@ void *jul_thread_manage_registration(void *data)
        rcu_register_thread();
        rcu_thread_online();
 
+       /* JUL initialization call MUST be called before starting the thread. */
+       assert(jul_apps_ht_by_sock);
+
        /* Create pollset with size 2, quit pipe and socket. */
        ret = sessiond_set_thread_pollset(&events, 2);
        if (ret < 0) {
@@ -150,6 +293,7 @@ restart:
                        goto error;
                }
                nb_fd = ret;
+               DBG3("[jul-thread] %d fd ready", nb_fd);
 
                for (i = 0; i < nb_fd; i++) {
                        /* Fetch once the poll data */
@@ -173,12 +317,34 @@ restart:
                                        goto error;
                                }
 
-                               /* FIXME: Nullify the JUL socket for the associated ust app. */
-                       } else if (revents & (LPOLLIN | LPOLLPRI)) {
                                /*
-                                * FIXME: Handle JUL registration which must link an UST-app
-                                * and this JUL socket.
+                                * FIXME: Should we try to invalidate the JUL socket in the
+                                * associated ust app.
                                 */
+                               destroy_jul_app(pollfd);
+                       } else if (revents & (LPOLLIN)) {
+                               int new_fd;
+
+                               /* Pollin event of JUL app socket should NEVER happen. */
+                               assert(pollfd == reg_sock->fd);
+
+                               new_fd = handle_registration(reg_sock);
+                               if (new_fd < 0) {
+                                       WARN("[jul-thread] JUL registration failed. Ignoring.");
+                                       /* Somehow the communication failed. Just continue. */
+                                       continue;
+                               }
+
+                               /* Only add poll error event to only detect shutdown. */
+                               ret = lttng_poll_add(&events, new_fd,
+                                               LPOLLERR | LPOLLHUP | LPOLLRDHUP);
+                               if (ret < 0) {
+                                       destroy_jul_app(new_fd);
+                                       continue;
+                               }
+
+                               /* Update newly registered app. */
+                               update_jul_app(new_fd);
                        } else {
                                ERR("Unknown poll events %u for sock %d", revents, pollfd);
                                continue;
@@ -187,6 +353,8 @@ restart:
        }
 
 exit:
+       /* Whatever happens, try to delete it and exit. */
+       (void) lttng_poll_del(&events, reg_sock->fd);
 error:
        destroy_tcp_socket(reg_sock);
 error_tcp_socket:
@@ -194,6 +362,11 @@ error_tcp_socket:
 error_poll_create:
        DBG("[jul-thread] is cleaning up and stopping.");
 
+       if (jul_apps_ht_by_sock) {
+               clean_jul_apps_ht();
+               lttng_ht_destroy(jul_apps_ht_by_sock);
+       }
+
        rcu_thread_offline();
        rcu_unregister_thread();
        return NULL;
index a38738c3b77537bfb711dbc160af69f892d02c1a..87ab654a34f3c109ce7c477fe6b51eb1892ade0d 100644 (file)
 
 #define _GNU_SOURCE
 #include <assert.h>
+#include <urcu/uatomic.h>
 
 #include <common/common.h>
+#include <common/sessiond-comm/jul.h>
 
 #include "jul.h"
+#include "ust-app.h"
 #include "utils.h"
 
 /*
@@ -36,6 +39,511 @@ static void destroy_event_jul_rcu(struct rcu_head *head)
        free(event);
 }
 
+/*
+ * URCU intermediate call to complete destroy a JUL event.
+ */
+static void destroy_app_jul_rcu(struct rcu_head *head)
+{
+       struct lttng_ht_node_ulong *node =
+               caa_container_of(head, struct lttng_ht_node_ulong, head);
+       struct jul_app *app =
+               caa_container_of(node, struct jul_app, node);
+
+       free(app);
+}
+
+/*
+ * Communication with Java agent call. Send the message header to the given
+ * socket all in big endian.
+ *
+ * Return 0 on success or else a negative errno message of sendmsg() op.
+ */
+static int send_header(struct lttcomm_sock *sock, uint64_t data_size,
+               uint32_t cmd, uint32_t cmd_version)
+{
+       int ret;
+       ssize_t size;
+       struct lttcomm_jul_hdr msg;
+
+       assert(sock);
+
+       msg.data_size = htobe64(data_size);
+       msg.cmd = htobe32(cmd);
+       msg.cmd_version = htobe32(cmd_version);
+
+       size = sock->ops->sendmsg(sock, &msg, sizeof(msg), 0);
+       if (size < sizeof(msg)) {
+               ret = -errno;
+               goto error;
+       }
+       ret = 0;
+
+error:
+       return ret;
+}
+
+/*
+ * Communication call with the Java agent. Send the payload to the given
+ * socket. The header MUST be sent prior to this call.
+ *
+ * Return 0 on success or else a negative errno value of sendmsg() op.
+ */
+static int send_payload(struct lttcomm_sock *sock, void *data,
+               size_t size)
+{
+       int ret;
+       ssize_t len;
+
+       assert(sock);
+       assert(data);
+
+       len = sock->ops->sendmsg(sock, data, size, 0);
+       if (len < size) {
+               ret = -errno;
+               goto error;
+       }
+       ret = 0;
+
+error:
+       return ret;
+}
+
+/*
+ * Communication call with the Java agent. Receive reply from the agent using
+ * the given socket.
+ *
+ * Return 0 on success or else a negative errno value from recvmsg() op.
+ */
+static int recv_reply(struct lttcomm_sock *sock, void *buf, size_t size)
+{
+       int ret;
+       ssize_t len;
+
+       assert(sock);
+       assert(buf);
+
+       len = sock->ops->recvmsg(sock, buf, size, 0);
+       if (len < size) {
+               ret = -errno;
+               goto error;
+       }
+       ret = 0;
+
+error:
+       return ret;
+}
+
+/*
+ * Internal enable JUL event call on a JUL application. This function
+ * communicates with the Java agent to enable a given event (Logger name).
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+static int enable_event(struct jul_app *app, struct jul_event *event)
+{
+       int ret;
+       uint64_t data_size;
+       struct lttcomm_jul_enable msg;
+       struct lttcomm_jul_generic_reply reply;
+
+       assert(app);
+       assert(app->sock);
+       assert(event);
+
+       DBG2("JUL enabling event %s for app pid: %d and socket %d", event->name,
+                       app->pid, app->sock->fd);
+
+       data_size = sizeof(msg);
+
+       ret = send_header(app->sock, data_size, JUL_CMD_ENABLE, 0);
+       if (ret < 0) {
+               goto error_io;
+       }
+
+       strncpy(msg.name, event->name, sizeof(msg.name));
+       ret = send_payload(app->sock, &msg, sizeof(msg));
+       if (ret < 0) {
+               goto error_io;
+       }
+
+       ret = recv_reply(app->sock, &reply, sizeof(reply));
+       if (ret < 0) {
+               goto error_io;
+       }
+
+       switch (be32toh(reply.ret_code)) {
+       case JUL_RET_CODE_SUCCESS:
+               break;
+       case JUL_RET_CODE_UNKNOWN_NAME:
+               ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+               goto error;
+       default:
+               ERR("Java agent returned an unknown code: %" PRIu32,
+                               be32toh(reply.ret_code));
+               ret = LTTNG_ERR_FATAL;
+               goto error;
+       }
+
+       return LTTNG_OK;
+
+error_io:
+       ret = LTTNG_ERR_UST_ENABLE_FAIL;
+error:
+       return ret;
+}
+
+/*
+ * Internal disable JUL event call on a JUL application. This function
+ * communicates with the Java agent to disable a given event (Logger name).
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+static int disable_event(struct jul_app *app, struct jul_event *event)
+{
+       int ret;
+       uint64_t data_size;
+       struct lttcomm_jul_disable msg;
+       struct lttcomm_jul_generic_reply reply;
+
+       assert(app);
+       assert(app->sock);
+       assert(event);
+
+       DBG2("JUL disabling event %s for app pid: %d and socket %d", event->name,
+                       app->pid, app->sock->fd);
+
+       data_size = sizeof(msg);
+
+       ret = send_header(app->sock, data_size, JUL_CMD_DISABLE, 0);
+       if (ret < 0) {
+               goto error_io;
+       }
+
+       strncpy(msg.name, event->name, sizeof(msg.name));
+       ret = send_payload(app->sock, &msg, sizeof(msg));
+       if (ret < 0) {
+               goto error_io;
+       }
+
+       ret = recv_reply(app->sock, &reply, sizeof(reply));
+       if (ret < 0) {
+               goto error_io;
+       }
+
+       switch (be32toh(reply.ret_code)) {
+               case JUL_RET_CODE_SUCCESS:
+                       break;
+               case JUL_RET_CODE_UNKNOWN_NAME:
+                       ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+                       goto error;
+               default:
+                       ERR("Java agent returned an unknown code: %" PRIu32,
+                                       be32toh(reply.ret_code));
+                       ret = LTTNG_ERR_FATAL;
+                       goto error;
+       }
+
+       return LTTNG_OK;
+
+error_io:
+       ret = LTTNG_ERR_UST_DISABLE_FAIL;
+error:
+       return ret;
+}
+
+/*
+ * Enable JUL event on every JUL applications registered with the session
+ * daemon.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int jul_enable_event(struct jul_event *event)
+{
+       int ret;
+       struct jul_app *app;
+       struct lttng_ht_iter iter;
+
+       assert(event);
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(jul_apps_ht_by_sock->ht, &iter.iter, app,
+                       node.node) {
+               /* Enable event on JUL application through TCP socket. */
+               ret = enable_event(app, event);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+               event->enabled = 1;
+       }
+
+       ret = LTTNG_OK;
+
+error:
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * Disable JUL event on every JUL applications registered with the session
+ * daemon.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int jul_disable_event(struct jul_event *event)
+{
+       int ret;
+       struct jul_app *app;
+       struct lttng_ht_iter iter;
+
+       assert(event);
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(jul_apps_ht_by_sock->ht, &iter.iter, app,
+                       node.node) {
+               /* Enable event on JUL application through TCP socket. */
+               ret = disable_event(app, event);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+               event->enabled = 0;
+       }
+
+       ret = LTTNG_OK;
+
+error:
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * Ask every java agent for the list of possible event (logger name). Events is
+ * allocated with the events of every JUL application.
+ *
+ * Return the number of events or else a negative value.
+ */
+int jul_list_events(struct lttng_event **events)
+{
+       int ret;
+       size_t nbmem, count = 0;
+       struct jul_app *app;
+       struct lttng_event *tmp_events;
+       struct lttng_ht_iter iter;
+
+       assert(events);
+
+       nbmem = UST_APP_EVENT_LIST_SIZE;
+       tmp_events = zmalloc(nbmem * sizeof(*tmp_events));
+       if (!tmp_events) {
+               PERROR("zmalloc jul list events");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       rcu_read_lock();
+       cds_lfht_for_each_entry(jul_apps_ht_by_sock->ht, &iter.iter, app,
+                       node.node) {
+               ssize_t nb_ev;
+               struct lttng_event *jul_events;
+
+               nb_ev = list_events(app, &jul_events);
+               if (nb_ev < 0) {
+                       ret = nb_ev;
+                       rcu_read_unlock();
+                       goto error;
+               }
+
+               if (count >= nbmem) {
+                       /* In case the realloc fails, we free the memory */
+                       void *ptr;
+
+                       DBG2("Reallocating JUL event list from %zu to %zu entries", nbmem,
+                                       2 * nbmem);
+                       nbmem *= 2;
+                       ptr = realloc(tmp_events, nbmem * sizeof(*tmp_events));
+                       if (!ptr) {
+                               PERROR("realloc JUL events");
+                               free(tmp_events);
+                               ret = -ENOMEM;
+                               rcu_read_unlock();
+                               goto error;
+                       }
+                       tmp_events = ptr;
+               }
+               memcpy(tmp_events + (count * sizeof(*tmp_events)), jul_events,
+                               nb_ev * sizeof(*tmp_events));
+               free(jul_events);
+               count += nb_ev;
+       }
+       rcu_read_unlock();
+
+       ret = count;
+       *events = tmp_events;
+
+error:
+       return ret;
+}
+
+/*
+ * Create a JUL app object using the given PID.
+ *
+ * Return newly allocated object or else NULL on error.
+ */
+struct jul_app *jul_create_app(pid_t pid, struct lttcomm_sock *sock)
+{
+       struct jul_app *app;
+
+       assert(sock);
+
+       app = zmalloc(sizeof(*app));
+       if (!app) {
+               PERROR("zmalloc JUL create");
+               goto error;
+       }
+
+       app->pid = pid;
+       app->sock = sock;
+       /* Flag it invalid until assignation. */
+       app->ust_app_sock = -1;
+       lttng_ht_node_init_ulong(&app->node, (unsigned long) app->sock->fd);
+
+error:
+       return app;
+}
+
+/*
+ * Lookup JUL app by socket in the global hash table.
+ *
+ * RCU read side lock MUST be acquired.
+ *
+ * Return object if found else NULL.
+ */
+struct jul_app *jul_find_app_by_sock(int sock)
+{
+       struct lttng_ht_node_ulong *node;
+       struct lttng_ht_iter iter;
+       struct jul_app *app;
+
+       assert(sock >= 0);
+
+       lttng_ht_lookup(jul_apps_ht_by_sock, (void *)((unsigned long) sock), &iter);
+       node = lttng_ht_iter_get_node_ulong(&iter);
+       if (node == NULL) {
+               goto error;
+       }
+       app = caa_container_of(node, struct jul_app, node);
+
+       DBG3("JUL app pid %d found by sock %d.", app->pid, sock);
+       return app;
+
+error:
+       DBG3("JUL app NOT found by sock %d.", sock);
+       return NULL;
+}
+
+/*
+ * Add JUL application object to a given hash table.
+ */
+void jul_add_app(struct jul_app *app)
+{
+       assert(app);
+
+       DBG3("JUL adding app sock: %d and pid: %d to ht", app->sock->fd, app->pid);
+
+       rcu_read_lock();
+       lttng_ht_add_unique_ulong(jul_apps_ht_by_sock, &app->node);
+       rcu_read_unlock();
+}
+
+/*
+ * Attach a given JUL application to an UST app object. This is done by copying
+ * the socket fd value into the ust app obj. atomically.
+ */
+void jul_attach_app(struct jul_app *japp)
+{
+       struct ust_app *uapp;
+
+       assert(japp);
+
+       rcu_read_lock();
+       uapp = ust_app_find_by_pid(japp->pid);
+       if (!uapp) {
+               goto end;
+       }
+
+       uatomic_set(&uapp->jul_app_sock, japp->sock->fd);
+
+       DBG3("JUL app pid: %d, sock: %d attached to UST app.", japp->pid,
+                       japp->sock->fd);
+
+end:
+       rcu_read_unlock();
+       return;
+}
+
+/*
+ * Remove JUL app. reference from an UST app object and set it to NULL.
+ */
+void jul_detach_app(struct jul_app *japp)
+{
+       struct ust_app *uapp;
+
+       assert(japp);
+
+       rcu_read_lock();
+
+       if (japp->ust_app_sock < 0) {
+               goto end;
+       }
+
+       uapp = ust_app_find_by_sock(japp->ust_app_sock);
+       if (!uapp) {
+               goto end;
+       }
+
+       uapp->jul_app_sock = -1;
+
+end:
+       rcu_read_unlock();
+       return;
+}
+
+/*
+ * Delete JUL application from the global hash table.
+ */
+void jul_delete_app(struct jul_app *app)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(app);
+
+       DBG3("JUL deleting app pid: %d and sock: %d", app->pid, app->sock->fd);
+
+       iter.iter.node = &app->node.node;
+       rcu_read_lock();
+       ret = lttng_ht_del(jul_apps_ht_by_sock, &iter);
+       rcu_read_unlock();
+       assert(!ret);
+}
+
+/*
+ * Destroy a JUL application object by detaching it from its corresponding UST
+ * app if one, closing the socket and freeing the memory.
+ */
+void jul_destroy_app(struct jul_app *app)
+{
+       assert(app);
+
+       if (app->sock) {
+               app->sock->ops->close(app->sock);
+               lttcomm_destroy_sock(app->sock);
+       }
+
+       call_rcu(&app->node.head, destroy_app_jul_rcu);
+}
+
 /*
  * Initialize an already allocated JUL domain object.
  *
@@ -79,6 +587,7 @@ struct jul_event *jul_create_event(const char *name)
        if (name) {
                strncpy(event->name, name, sizeof(event->name));
                event->name[sizeof(event->name) - 1] = '\0';
+               lttng_ht_node_init_str(&event->node, event->name);
        }
 
 error:
@@ -96,7 +605,9 @@ void jul_add_event(struct jul_event *event, struct jul_domain *dom)
 
        DBG3("JUL adding event %s to domain", event->name);
 
+       rcu_read_lock();
        lttng_ht_add_unique_str(dom->events, &event->node);
+       rcu_read_unlock();
 }
 
 /*
@@ -191,5 +702,61 @@ void jul_destroy_domain(struct jul_domain *dom)
        }
        rcu_read_unlock();
 
-       ht_cleanup_push(dom->events);
+       lttng_ht_destroy(dom->events);
+}
+
+/*
+ * Initialize JUL subsystem.
+ */
+int jul_init(void)
+{
+       jul_apps_ht_by_sock = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+       if (!jul_apps_ht_by_sock) {
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Update a JUL application (given socket) using the given domain.
+ *
+ * Note that this function is most likely to be used with a tracing session
+ * thus the caller should make sure to hold the appropriate lock(s).
+ */
+void jul_update(struct jul_domain *domain, int sock)
+{
+       int ret;
+       struct jul_app *app;
+       struct jul_event *event;
+       struct lttng_ht_iter iter;
+
+       assert(domain);
+       assert(sock >= 0);
+
+       DBG("JUL updating app socket %d", sock);
+
+       rcu_read_lock();
+       cds_lfht_for_each_entry(domain->events->ht, &iter.iter, event, node.node) {
+               /* Skip event if disabled. */
+               if (!event->enabled) {
+                       continue;
+               }
+
+               app = jul_find_app_by_sock(sock);
+               /*
+                * We are in the registration path thus if the application is gone,
+                * there is a serious code flow error.
+                */
+               assert(app);
+
+               ret = enable_event(app, event);
+               if (ret != LTTNG_OK) {
+                       DBG2("JUL update unable to enable event %s on app pid: %d sock %d",
+                                       event->name, app->pid, app->sock->fd);
+                       /* Let's try the others here and don't assume the app is dead. */
+                       continue;
+               }
+       }
+       rcu_read_unlock();
 }
index 1f7f6cdcd8e0a176e31095526882c20f51fc528d..f7d3c48f8d078afd83eb4f015c3d6cb8ad3e3c72 100644 (file)
 #ifndef _JUL_H
 #define _JUL_H
 
+#define _GNU_SOURCE
+#include <inttypes.h>
+
 #include <common/hashtable/hashtable.h>
 #include <lttng/lttng.h>
 
+/*
+ * Hash table that contains the JUL app created upon registration indexed by
+ * socket.
+ */
+struct lttng_ht *jul_apps_ht_by_sock;
+
+/*
+ * Registration message payload from a JUL application. The PID is used to find
+ * back the corresponding UST app object so both socket can be linked.
+ */
+struct jul_register_msg {
+       uint32_t pid;
+};
+
+/*
+ * JUL application object created after a successful registration. This object
+ * is kept inside an UST app.
+ */
+struct jul_app {
+       /*
+        * PID sent during registration of a JUL application.
+        */
+       pid_t pid;
+
+       /*
+        * JUL TCP socket that was created upon registration.
+        */
+       struct lttcomm_sock *sock;
+
+       /*
+        * Associated UST app. socket. To get a reference to the ust application
+        * object corresponding to that socket, a lookup MUST be done each time
+        * since there is important synchronization issue for the lockless hash
+        * table shared accross multiple threads.
+        */
+       int ust_app_sock;
+
+       /* Initialized with the JUL sock value. */
+       struct lttng_ht_node_ulong node;
+};
+
 /*
  * Java Util Logging event representation.
  */
@@ -53,12 +97,32 @@ struct jul_domain {
        struct lttng_ht *events;
 };
 
+/* Initialize JUL domain subsystem. */
+int jul_init(void);
+
+/* Initialize an already allocated JUL domain. */
 int jul_init_domain(struct jul_domain *dom);
+void jul_destroy_domain(struct jul_domain *dom);
+
+/* JUL event API. */
 struct jul_event *jul_create_event(const char *name);
 void jul_add_event(struct jul_event *event, struct jul_domain *dom);
 struct jul_event *jul_find_by_name(const char *name, struct jul_domain *dom);
 void jul_delete_event(struct jul_event *event, struct jul_domain *dom);
 void jul_destroy_event(struct jul_event *event);
-void jul_destroy_domain(struct jul_domain *dom);
+
+/* JUL app API. */
+struct jul_app *jul_create_app(pid_t pid, struct lttcomm_sock *sock);
+void jul_add_app(struct jul_app *app);
+void jul_delete_app(struct jul_app *app);
+struct jul_app *jul_find_app_by_sock(int sock);
+void jul_attach_app(struct jul_app *japp);
+void jul_detach_app(struct jul_app *app);
+void jul_destroy_app(struct jul_app *app);
+
+/* JUL action API */
+int jul_enable_event(struct jul_event *event);
+int jul_disable_event(struct jul_event *event);
+void jul_update(struct jul_domain *domain, int sock);
 
 #endif /* _JUL_H */
index 6d6140b1f891f10c75f4cff539c0f6776b7272aa..05646279a63a48b3f81bbf64d67454b9aaf53a1c 100644 (file)
@@ -2415,6 +2415,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session)
                consumer = session->kernel_session->consumer;
                dir_name = DEFAULT_KERNEL_TRACE_DIR;
                break;
+       case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_UST:
                DBG3("Copying tracing session consumer output in UST session");
                if (session->ust_session->consumer) {
@@ -2458,6 +2459,7 @@ static int create_ust_session(struct ltt_session *session,
        assert(session->consumer);
 
        switch (domain->type) {
+       case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_UST:
                break;
        default:
@@ -2750,10 +2752,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
 
                break;
        case LTTNG_DOMAIN_JUL:
-       {
-               ret = LTTNG_ERR_UNKNOWN_DOMAIN;
-               goto error;
-       }
        case LTTNG_DOMAIN_UST:
        {
                if (!ust_app_supported()) {
@@ -4628,6 +4626,12 @@ int main(int argc, char **argv)
         */
        ust_app_ht_alloc();
 
+       /* Initialize JUL domain subsystem. */
+       if ((ret = jul_init()) < 0) {
+               /* ENOMEM at this point. */
+               goto error;
+       }
+
        /* After this point, we can safely call cleanup() with "goto exit" */
 
        /*
index 5464880fc3756dec6381b03c0cc2c503bd5b64ea..11b588f77f675aef1a60d9a3c265cec76f2fb4bf 100644 (file)
@@ -957,8 +957,7 @@ error:
  * Find an ust_app using the sock and return it. RCU read side lock must be
  * held before calling this helper function.
  */
-static
-struct ust_app *find_app_by_sock(int sock)
+struct ust_app *ust_app_find_by_sock(int sock)
 {
        struct lttng_ht_node_ulong *node;
        struct lttng_ht_iter iter;
@@ -4152,7 +4151,7 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock)
 
        rcu_read_lock();
 
-       app = find_app_by_sock(sock);
+       app = ust_app_find_by_sock(sock);
        if (app == NULL) {
                /*
                 * Application can be unregistered before so this is possible hence
index edec8d49639eb25b61f02664847e9ef2cea29def..249d568d1fb66f31aaf15cd65fe786e0c17f398e 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdint.h>
 
 #include <common/compat/uuid.h>
+
+#include "jul.h"
 #include "trace-ust.h"
 #include "ust-registry.h"
 
@@ -259,6 +261,13 @@ struct ust_app {
         * Hash table containing ust_app_channel indexed by channel objd.
         */
        struct lttng_ht *ust_objd;
+       /*
+        * If this application is of the JUL domain and this is non negative then a
+        * lookup MUST be done to acquire a read side reference to the
+        * corresponding JUL app object. If the lookup fails, this should be set to
+        * a negative value indicating that the JUL application is gone.
+        */
+       int jul_app_sock;
 };
 
 #ifdef HAVE_LIBLTTNG_UST_CTL
@@ -320,6 +329,7 @@ void ust_app_destroy(struct ust_app *app);
 int ust_app_snapshot_record(struct ltt_ust_session *usess,
                struct snapshot_output *output, int wait, unsigned int nb_streams);
 unsigned int ust_app_get_nb_stream(struct ltt_ust_session *usess);
+struct ust_app *ust_app_find_by_sock(int sock);
 
 static inline
 int ust_app_supported(void)
@@ -540,6 +550,11 @@ int ust_app_supported(void)
 {
        return 0;
 }
+static inline
+struct ust_app *ust_app_find_by_sock(int sock)
+{
+       return NULL;
+}
 
 #endif /* HAVE_LIBLTTNG_UST_CTL */
 
index 0010e0616bd18862ab2cb5459709871d2a1571e9..821128eb4df197539d334fb7b5fe67988c022296 100644 (file)
 /* Default channel attributes */
 #define DEFAULT_CHANNEL_NAME            "channel0"
 /* Default JUL domain channel name. */
-#define DEFAULT_JUL_CHANNEL_NAME        "jul_channel"
+#define DEFAULT_JUL_CHANNEL_NAME        "lttng_jul_channel"
+/* Default JUL tracepoint name. This is a wildcard for the JUL domain. */
+#define DEFAULT_JUL_EVENT_NAME          "lttng_jul*"
 /* JUL default channel name. */
 #define DEFAULT_CHANNEL_OVERWRITE       0
 #define DEFAULT_CHANNEL_TRACEFILE_SIZE  0
index 72375c0e90a8b2a8448a01a1f3ea5a920a88021e..c72c87fbcd4a20897afabe25745044f98c7fe435 100644 (file)
@@ -5,5 +5,5 @@ noinst_LTLIBRARIES = libsessiond-comm.la
 
 libsessiond_comm_la_SOURCES = sessiond-comm.c sessiond-comm.h \
                               unix.c unix.h inet.c inet.h inet6.c inet6.h \
-                              relayd.h
+                              relayd.h jul.h
 libsessiond_comm_la_LIBADD = -lrt
diff --git a/src/common/sessiond-comm/jul.h b/src/common/sessiond-comm/jul.h
new file mode 100644 (file)
index 0000000..fa14dbf
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _JUL_COMM
+#define _JUL_COMM
+
+#define _GNU_SOURCE
+#include <stdint.h>
+
+#include <lttng/lttng.h>
+
+/*
+ * Command value pass in the header.
+ */
+enum lttcomm_jul_command {
+       JUL_CMD_LIST       = 1,
+       JUL_CMD_ENABLE     = 2,
+       JUL_CMD_DISABLE    = 3,
+};
+
+/*
+ * Return code from the Java agent.
+ */
+enum lttcomm_jul_ret_code {
+       JUL_RET_CODE_SUCCESS      = 1,
+       JUL_RET_CODE_INVALID      = 2,
+       JUL_RET_CODE_UNKNOWN_NAME = 3,
+};
+
+/*
+ * JUL application communication header.
+ */
+struct lttcomm_jul_hdr {
+       uint64_t data_size;             /* data size following this header */
+       uint32_t cmd;                   /* Enum of JUL command. */
+       uint32_t cmd_version;   /* command version */
+} LTTNG_PACKED;
+
+/*
+ * Enable event command payload.
+ */
+struct lttcomm_jul_enable {
+       char name[LTTNG_SYMBOL_NAME_LEN];
+} LTTNG_PACKED;
+
+/*
+ * Disable event command payload.
+ */
+struct lttcomm_jul_disable {
+       char name[LTTNG_SYMBOL_NAME_LEN];
+} LTTNG_PACKED;
+
+/*
+ * Generic reply coming from the Java Agent.
+ */
+struct lttcomm_jul_generic_reply {
+       uint32_t ret_code;
+} LTTNG_PACKED;
+
+/*
+ * List command reply header.
+ */
+struct lttcomm_jul_list_reply_hdr {
+       uint32_t ret_code;
+       uint32_t data_size;
+} LTTNG_PACKED;
+
+/*
+ * List command reply payload coming from the Java Agent.
+ */
+struct lttcomm_jul_list_reply {
+       uint32_t nb_event;
+       /* List of event name each of them ending by a NULL byte. */
+       char payload[];
+} LTTNG_PACKED;
+
+#endif /* _JUL_COMM */
This page took 0.045682 seconds and 4 git commands to generate.