that, the kernel version may probably be older, but we can't provide
any guarantee. Please let us know if you are able to go lower
without any problems.
- - **[`liburcu`](http://www.liburcu.org/) >= 0.8.0**: userspace RCU library,
+ - **[`liburcu`](http://www.liburcu.org/) >= 0.9.0**: userspace RCU library,
by Mathieu Desnoyers and Paul E. McKenney.
- **`libpopt` >= 1.13**: command line arguments parsing library.
- Debian/Ubuntu package: `libpopt-dev`
AC_CHECK_FUNC([clock_gettime], [AC_DEFINE_UNQUOTED([LTTNG_HAVE_CLOCK_GETTIME], 1, [Has clock_gettime() support.])])
# URCU library version needed or newer
-m4_define([WRONG_LIBURCU_MSG], [Userspace RCU (liburcu) >= 0.8.0 is needed])
+m4_define([WRONG_LIBURCU_MSG], [Userspace RCU (liburcu) >= 0.9.0 is needed])
# Check liburcu needed function calls
AC_CHECK_DECL([cds_list_add], [],
[AC_MSG_ERROR([WRONG_LIBURCU_MSG])], [[#include <urcu.h>]]
)
+#Function added in urcu 0.9.0
+AC_CHECK_DECL([urcu_ref_get_unless_zero], [],
+ [AC_MSG_ERROR([WRONG_LIBURCU_MSG])], [[#include <urcu/ref.h>]]
+)
+
# Check kmod library
AC_ARG_WITH(kmod-prefix,
AS_HELP_STRING([--with-kmod-prefix=PATH],
scheme allows looking up the objects or doing a traversal on the RCU
linked list or hash table in combination with a getter on the object.
This getter validates that there is still at least one reference to the
-object, else the lookup acts just as if the object does not exist. This
-scheme is protected by a "reflock" mutex in each object. "reflock"
-mutexes can be nested from the innermost object to the outermost object.
-IOW, the session reflock can nest within the ctf-trace reflock.
+object, else the lookup acts just as if the object does not exist.
The relay_connection (connection between the sessiond/consumer and the
relayd) is the outermost object of its hierarchy.
the outermost object to the innermost object. IOW, the ctf-trace lock can
nest within the session lock.
-A "lock" should never nest within a "reflock".
-
RCU linked lists are used to iterate using RCU, and are protected by
their own mutex for modifications. Iterations should be confirmed using
the object "getter" to ensure its refcount is not 0 (except in cases
bool connection_get(struct relay_connection *conn)
{
- bool has_ref = false;
-
- pthread_mutex_lock(&conn->reflock);
- if (conn->ref.refcount != 0) {
- has_ref = true;
- urcu_ref_get(&conn->ref);
- }
- pthread_mutex_unlock(&conn->reflock);
-
- return has_ref;
+ return urcu_ref_get_unless_zero(&conn->ref);
}
struct relay_connection *connection_get_by_sock(struct lttng_ht *relay_connections_ht,
PERROR("zmalloc relay connection");
goto end;
}
- pthread_mutex_init(&conn->reflock, NULL);
urcu_ref_init(&conn->ref);
conn->type = type;
conn->sock = sock;
void connection_put(struct relay_connection *conn)
{
rcu_read_lock();
- pthread_mutex_lock(&conn->reflock);
urcu_ref_put(&conn->ref, connection_release);
- pthread_mutex_unlock(&conn->reflock);
rcu_read_unlock();
}
uint32_t minor;
struct urcu_ref ref;
- pthread_mutex_t reflock;
bool version_check_done;
*/
bool ctf_trace_get(struct ctf_trace *trace)
{
- bool has_ref = false;
-
- /* Confirm that the trace refcount has not reached 0. */
- pthread_mutex_lock(&trace->reflock);
- if (trace->ref.refcount != 0) {
- has_ref = true;
- urcu_ref_get(&trace->ref);
- }
- pthread_mutex_unlock(&trace->reflock);
-
- return has_ref;
+ return urcu_ref_get_unless_zero(&trace->ref);
}
/*
trace->session = session;
urcu_ref_init(&trace->ref);
pthread_mutex_init(&trace->lock, NULL);
- pthread_mutex_init(&trace->reflock, NULL);
pthread_mutex_init(&trace->stream_list_lock, NULL);
lttng_ht_add_str(session->ctf_traces_ht, &trace->node);
void ctf_trace_put(struct ctf_trace *trace)
{
rcu_read_lock();
- pthread_mutex_lock(&trace->reflock);
urcu_ref_put(&trace->ref, ctf_trace_release);
- pthread_mutex_unlock(&trace->reflock);
rcu_read_unlock();
}
#include "viewer-stream.h"
struct ctf_trace {
- /*
- * The ctf_trace reflock nests inside the stream reflock.
- */
- pthread_mutex_t reflock; /* Protects refcounting */
struct urcu_ref ref; /* Every stream has a ref on the trace. */
struct relay_session *session; /* Back ref to trace session */
lttng_ht_node_init_u64(&index->index_n, net_seq_num);
pthread_mutex_init(&index->lock, NULL);
- pthread_mutex_init(&index->reflock, NULL);
urcu_ref_init(&index->ref);
end:
*/
static bool relay_index_get(struct relay_index *index)
{
- bool has_ref = false;
-
DBG2("index get for stream id %" PRIu64 " and seqnum %" PRIu64 " refcount %d",
index->stream->stream_handle, index->index_n.key,
(int) index->ref.refcount);
- /* Confirm that the index refcount has not reached 0. */
- pthread_mutex_lock(&index->reflock);
- if (index->ref.refcount != 0) {
- has_ref = true;
- urcu_ref_get(&index->ref);
- }
- pthread_mutex_unlock(&index->reflock);
-
- return has_ref;
+ return urcu_ref_get_unless_zero(&index->ref);
}
/*
* Index lock ensures that concurrent test and update of stream
* ref is atomic.
*/
- pthread_mutex_lock(&index->reflock);
assert(index->ref.refcount != 0);
urcu_ref_put(&index->ref, index_release);
- pthread_mutex_unlock(&index->reflock);
rcu_read_unlock();
}
/*
* index lock nests inside stream lock.
*/
- pthread_mutex_t reflock; /* Protects refcounting. */
struct urcu_ref ref; /* Reference from getters. */
struct relay_stream *stream; /* Back ref to stream */
urcu_ref_init(&session->ref);
CDS_INIT_LIST_HEAD(&session->recv_list);
pthread_mutex_init(&session->lock, NULL);
- pthread_mutex_init(&session->reflock, NULL);
pthread_mutex_init(&session->recv_list_lock, NULL);
session->live_timer = live_timer;
/* Should be called with RCU read-side lock held. */
bool session_get(struct relay_session *session)
{
- bool has_ref = false;
-
- pthread_mutex_lock(&session->reflock);
- if (session->ref.refcount != 0) {
- has_ref = true;
- urcu_ref_get(&session->ref);
- }
- pthread_mutex_unlock(&session->reflock);
-
- return has_ref;
+ return urcu_ref_get_unless_zero(&session->ref);
}
/*
void session_put(struct relay_session *session)
{
rcu_read_lock();
- pthread_mutex_lock(&session->reflock);
urcu_ref_put(&session->ref, session_release);
- pthread_mutex_unlock(&session->reflock);
rcu_read_unlock();
}
*/
struct urcu_ref ref;
- /* session reflock nests inside ctf_trace reflock. */
- pthread_mutex_t reflock;
pthread_mutex_t lock;
/* Should be called with RCU read-side lock held. */
bool stream_get(struct relay_stream *stream)
{
- bool has_ref = false;
-
- pthread_mutex_lock(&stream->reflock);
- if (stream->ref.refcount != 0) {
- has_ref = true;
- urcu_ref_get(&stream->ref);
- }
- pthread_mutex_unlock(&stream->reflock);
-
- return has_ref;
+ return urcu_ref_get_unless_zero(&stream->ref);
}
/*
stream->channel_name = channel_name;
lttng_ht_node_init_u64(&stream->node, stream->stream_handle);
pthread_mutex_init(&stream->lock, NULL);
- pthread_mutex_init(&stream->reflock, NULL);
urcu_ref_init(&stream->ref);
ctf_trace_get(trace);
stream->trace = trace;
/*
* Stream must be protected by holding the stream lock or by virtue of being
- * called from stream_destroy, in which case it is guaranteed to be accessed
- * from a single thread by the reflock.
+ * called from stream_destroy.
*/
static void stream_unpublish(struct relay_stream *stream)
{
/*
* No need to take stream->lock since this is only called on the final
* stream_put which ensures that a single thread may act on the stream.
- *
- * At that point, the object is also protected by the reflock which
- * guarantees that no other thread may share ownership of this stream.
*/
static void stream_release(struct urcu_ref *ref)
{
void stream_put(struct relay_stream *stream)
{
DBG("stream put for stream id %" PRIu64, stream->stream_handle);
- /*
- * Ensure existence of stream->reflock for stream unlock.
- */
rcu_read_lock();
- /*
- * Stream reflock ensures that concurrent test and update of
- * stream ref is atomic.
- */
- pthread_mutex_lock(&stream->reflock);
assert(stream->ref.refcount != 0);
/*
* Wait until we have processed all the stream packets before
stream->stream_handle,
(int) stream->ref.refcount);
urcu_ref_put(&stream->ref, stream_release);
- pthread_mutex_unlock(&stream->reflock);
rcu_read_unlock();
}
struct relay_stream {
uint64_t stream_handle;
- /*
- * reflock used to synchronize the closing of this stream.
- * stream reflock nests inside viewer stream reflock.
- * stream reflock nests inside index reflock.
- */
- pthread_mutex_t reflock;
struct urcu_ref ref;
/* Back reference to trace. Protected by refcount on trace object. */
struct ctf_trace *trace;
lttng_ht_node_init_u64(&vstream->stream_n, stream->stream_handle);
lttng_ht_add_unique_u64(viewer_streams_ht, &vstream->stream_n);
- pthread_mutex_init(&vstream->reflock, NULL);
urcu_ref_init(&vstream->ref);
return vstream;
/* Must be called with RCU read-side lock held. */
bool viewer_stream_get(struct relay_viewer_stream *vstream)
{
- bool has_ref = false;
-
- pthread_mutex_lock(&vstream->reflock);
- if (vstream->ref.refcount != 0) {
- has_ref = true;
- urcu_ref_get(&vstream->ref);
- }
- pthread_mutex_unlock(&vstream->reflock);
-
- return has_ref;
+ return urcu_ref_get_unless_zero(&vstream->ref);
}
/*
void viewer_stream_put(struct relay_viewer_stream *vstream)
{
rcu_read_lock();
- pthread_mutex_lock(&vstream->reflock);
urcu_ref_put(&vstream->ref, viewer_stream_release);
- pthread_mutex_unlock(&vstream->reflock);
rcu_read_unlock();
}
*/
struct relay_viewer_stream {
struct urcu_ref ref;
- pthread_mutex_t reflock;
/* Back ref to stream. */
struct relay_stream *stream;