#include <urcu.h>
#include <urcu/rculfhash.h>
-#include "notification-thread.h"
-#include "notification-thread-events.h"
-#include "notification-thread-commands.h"
#include <common/defaults.h>
#include <common/error.h>
#include <common/futex.h>
#include <lttng/condition/condition-internal.h>
#include <lttng/condition/buffer-usage-internal.h>
#include <lttng/notification/channel-internal.h>
+
#include <time.h>
#include <unistd.h>
#include <assert.h>
#include <inttypes.h>
#include <fcntl.h>
+#include "notification-thread.h"
+#include "notification-thread-events.h"
+#include "notification-thread-commands.h"
+#include "lttng-sessiond.h"
+#include "kernel.h"
+
#define CLIENT_POLL_MASK_IN (LPOLLIN | LPOLLERR | LPOLLHUP | LPOLLRDHUP)
#define CLIENT_POLL_MASK_IN_OUT (CLIENT_POLL_MASK_IN | LPOLLOUT)
struct cds_lfht_node client_socket_ht_node;
struct {
struct {
+ /*
+ * During the reception of a message, the reception
+ * buffers' "size" is set to contain the current
+ * message's complete payload.
+ */
struct lttng_dynamic_buffer buffer;
/* Bytes left to receive for the current message. */
size_t bytes_to_receive;
* Indicates whether or not credentials are expected
* from the client.
*/
- bool receive_creds;
+ bool expect_creds;
/*
* Indicates whether or not credentials were received
* from the client.
*/
bool creds_received;
+ /* Only used during credentials reception. */
lttng_sock_cred creds;
} inbound;
struct {
return 0;
}
+static
+int condition_is_supported(struct lttng_condition *condition)
+{
+ int ret;
+
+ switch (lttng_condition_get_type(condition)) {
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+ {
+ enum lttng_domain_type domain;
+
+ ret = lttng_condition_buffer_usage_get_domain_type(condition,
+ &domain);
+ if (ret) {
+ ret = -1;
+ goto end;
+ }
+
+ if (domain != LTTNG_DOMAIN_KERNEL) {
+ ret = 1;
+ goto end;
+ }
+
+ /*
+ * Older kernel tracers don't expose the API to monitor their
+ * buffers. Therefore, we reject triggers that require that
+ * mechanism to be available to be evaluated.
+ */
+ ret = kernel_supports_ring_buffer_snapshot_sample_positions(
+ kernel_tracer_fd);
+ break;
+ }
+ default:
+ ret = 1;
+ }
+end:
+ return ret;
+}
+
/*
* FIXME A client's credentials are not checked when registering a trigger, nor
* are they stored alongside with the trigger.
*
- * The effects of this are benign:
+ * The effects of this are benign since:
* - The client will succeed in registering the trigger, as it is valid,
* - The trigger will, internally, be bound to the channel,
* - The notifications will not be sent since the client's credentials
* are checked against the channel at that moment.
+ *
+ * If this function returns a non-zero value, it means something is
+ * fundamentally and the whole subsystem/thread will be torn down.
+ *
+ * If a non-fatal error occurs, just set the cmd_result to the appropriate
+ * error code.
*/
static
int handle_notification_thread_command_register_trigger(
rcu_read_lock();
condition = lttng_trigger_get_condition(trigger);
+ assert(condition);
+
+ ret = condition_is_supported(condition);
+ if (ret < 0) {
+ goto error;
+ } else if (ret == 0) {
+ *cmd_result = LTTNG_ERR_NOT_SUPPORTED;
+ goto error;
+ } else {
+ /* Feature is supported, continue. */
+ ret = 0;
+ }
+
trigger_ht_element = zmalloc(sizeof(*trigger_ht_element));
if (!trigger_ht_element) {
ret = -1;
}
end:
cds_list_del(&cmd->cmd_list_node);
- futex_nto1_wake(&cmd->reply_futex);
+ lttng_waiter_wake_up(&cmd->reply_waiter);
pthread_mutex_unlock(&handle->cmd_queue.lock);
return ret;
error_unlock:
/* Wake-up and return a fatal error to the calling thread. */
- futex_nto1_wake(&cmd->reply_futex);
+ lttng_waiter_wake_up(&cmd->reply_waiter);
pthread_mutex_unlock(&handle->cmd_queue.lock);
cmd->reply_code = LTTNG_ERR_FATAL;
error:
}
static
-void client_reset_inbound_state(struct notification_client *client)
+int client_reset_inbound_state(struct notification_client *client)
{
int ret;
sizeof(struct lttng_notification_channel_message);
client->communication.inbound.msg_type =
LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNKNOWN;
- client->communication.inbound.receive_creds = false;
LTTNG_SOCK_SET_UID_CRED(&client->communication.inbound.creds, -1);
LTTNG_SOCK_SET_GID_CRED(&client->communication.inbound.creds, -1);
+ ret = lttng_dynamic_buffer_set_size(
+ &client->communication.inbound.buffer,
+ client->communication.inbound.bytes_to_receive);
+ return ret;
}
int handle_notification_thread_client_connect(
CDS_INIT_LIST_HEAD(&client->condition_list);
lttng_dynamic_buffer_init(&client->communication.inbound.buffer);
lttng_dynamic_buffer_init(&client->communication.outbound.buffer);
- client_reset_inbound_state(client);
+ client->communication.inbound.expect_creds = true;
+ ret = client_reset_inbound_state(client);
+ if (ret) {
+ ERR("[notification-thread] Failed to reset client communication's inbound state");
+ ret = 0;
+ goto error;
+ }
ret = lttcomm_accept_unix_sock(state->notification_channel_socket);
if (ret < 0) {
DBG("[notification-thread] Added new notification channel client socket (%i) to poll set",
client->socket);
- /* Add to ht. */
rcu_read_lock();
cds_lfht_add(state->client_socket_ht,
hash_client_socket(client->socket),
int handle_notification_thread_trigger_unregister_all(
struct notification_thread_state *state)
{
- bool error_occured = false;
+ bool error_occurred = false;
struct cds_lfht_iter iter;
struct lttng_trigger_ht_element *trigger_ht_element;
int ret = handle_notification_thread_command_unregister_trigger(
state, trigger_ht_element->trigger, NULL);
if (ret) {
- error_occured = true;
+ error_occurred = true;
}
}
- return error_occured ? -1 : 0;
+ return error_occurred ? -1 : 0;
}
static
client->communication.inbound.bytes_to_receive = msg->size;
client->communication.inbound.msg_type =
(enum lttng_notification_channel_message_type) msg->type;
- if (client->communication.inbound.msg_type ==
- LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE) {
- client->communication.inbound.receive_creds = true;
- }
ret = lttng_dynamic_buffer_set_size(
- &client->communication.inbound.buffer, 0);
+ &client->communication.inbound.buffer, msg->size);
if (ret) {
goto end;
}
handshake_client =
(struct lttng_notification_channel_command_handshake *)
client->communication.inbound.buffer.data;
- client->major = handshake_client->major;
+ client->major = handshake_client->major;
client->minor = handshake_client->minor;
if (!client->communication.inbound.creds_received) {
ERR("[notification-thread] No credentials received from client");
}
/* Set reception state to receive the next message header. */
- client_reset_inbound_state(client);
+ ret = client_reset_inbound_state(client);
+ if (ret) {
+ ERR("[notification-thread] Failed to reset client communication's inbound state");
+ goto end;
+ }
client->validated = true;
break;
}
}
/* Set reception state to receive the next message header. */
- client_reset_inbound_state(client);
+ ret = client_reset_inbound_state(client);
+ if (ret) {
+ ERR("[notification-thread] Failed to reset client communication's inbound state");
+ goto end;
+ }
break;
}
default:
int handle_notification_thread_client_in(
struct notification_thread_state *state, int socket)
{
- int ret;
+ int ret = 0;
struct notification_client *client;
ssize_t recv_ret;
size_t offset;
goto end;
}
- offset = client->communication.inbound.buffer.size;
- ret = lttng_dynamic_buffer_set_size(
- &client->communication.inbound.buffer,
- client->communication.inbound.bytes_to_receive);
- if (ret) {
- goto end;
- }
-
- if (client->communication.inbound.receive_creds) {
+ offset = client->communication.inbound.buffer.size -
+ client->communication.inbound.bytes_to_receive;
+ if (client->communication.inbound.expect_creds) {
recv_ret = lttcomm_recv_creds_unix_sock(socket,
client->communication.inbound.buffer.data + offset,
client->communication.inbound.bytes_to_receive,
&client->communication.inbound.creds);
if (recv_ret > 0) {
- client->communication.inbound.receive_creds = false;
+ client->communication.inbound.expect_creds = false;
client->communication.inbound.creds_received = true;
}
} else {
}
client->communication.inbound.bytes_to_receive -= recv_ret;
- ret = lttng_dynamic_buffer_set_size(
- &client->communication.inbound.buffer,
- client->communication.inbound.buffer.size -
- client->communication.inbound.bytes_to_receive);
- if (ret) {
- goto end;
- }
-
if (client->communication.inbound.bytes_to_receive == 0) {
ret = client_dispatch_message(client, state);
if (ret) {