#include <malloc.h>
#include <string.h>
-#include <asm/atomic.h>
#include "lttng_usertrace.h"
#define MAX_TRACES 16
-struct ltt_buf {
- void *start;
- atomic_t offset;
- atomic_t reserve_count;
- atomic_t commit_count;
- atomic_t events_lost;
-};
-
-struct lttng_trace_info {
- int active:1;
- int filter;
- struct {
- struct ltt_buf facilities;
- struct ltt_buf cpu;
- } channel;
-};
+/*
+ * Notes :
+ *
+ * ltt_update :
+ *
+ * it should send the information on the traces that has their status MODIFIED.
+ * It's a necessary assumption to have a correct lttng_free_trace_info, which
+ * would not be reentrant otherwise.
+ */
/* TLS for the trace info
static __thread struct lttng_trace_info lttng_trace_info[MAX_TRACES] =
{ [ 0 ... MAX_TRACES-1 ].active = 0,
[ 0 ... MAX_TRACES-1 ].filter = 0,
+ [ 0 ... MAX_TRACES-1 ].destroy = 0,
+ [ 0 ... MAX_TRACES-1 ].nesting = ATOMIC_INIT(0),
[ 0 ... MAX_TRACES-1 ].channel =
{ NULL,
+ 0,
ATOMIC_INIT(0),
ATOMIC_INIT(0),
ATOMIC_INIT(0),
};
+/* Must be called we sure nobody else is using the info.
+ * It implies that the trace should have been previously stopped
+ * and that every writer has finished.
+ *
+ * Writers should always check if the trace must be destroyed when they
+ * finish writing and the nesting level is 0.
+ */
+void lttng_free_trace_info(struct lttng_trace_info *info)
+{
+ int ret;
+
+ if(info->active) {
+ printf(
+ "LTTng ERROR : lttng_free_trace_info should be called on inactive trace\n");
+ exit(1);
+ }
+ if(!info->destroy) {
+ printf(
+ "LTTng ERROR : lttng_free_trace_info should be called on destroyed trace\n");
+ exit(1);
+ }
+ if(atomic_read(&info->nesting) > 0) {
+ printf(
+ "LTTng ERROR : lttng_free_trace_info should not be nested on tracing\n");
+ exit(1);
+ }
+
+ /* Remove the maps */
+ ret = munmap(info->channel.cpu.start, info->channel.cpu.length);
+ if(ret) {
+ perror("LTTNG : error in munmap");
+ }
+ ret = munmap(info->channel.facilities.start, info->channel.facilities.length);
+ if(ret) {
+ perror("LTTNG : error in munmap");
+ }
+
+ /* Zero the structure */
+ memset(info, 0, sizeof(struct lttng_trace_info));
+}
+
+
+static struct lttng_trace_info* find_info(unsigned long cpu_addr,
+ unsigned long fac_addr, unsigned int *first_empty)
+{
+ struct lttng_trace_info *found = NULL;
+ unsigned int i;
+
+ *first_empty = MAX_TRACES;
+
+ /* Try to find the trace */
+ for(i=0;i<MAX_TRACES;i++) {
+ if(i<*first_empty && !lttng_trace_info[i].channel.cpu.start)
+ *first_empty = i;
+ if(cpu_addr ==
+ (unsigned long)lttng_trace_info[i].channel.cpu.start &&
+ fac_addr ==
+ (unsigned long)lttng_trace_info[i].channel.facilities.start) {
+ /* Found */
+ found = <tng_trace_info[i];
+ break;
+ }
+ }
+ return found;
+}
+
+
static void lttng_get_new_info(void)
{
unsigned long cpu_addr, fac_addr;
unsigned int i, first_empty;
- int active, filter;
+ int active, filter, destroy;
int ret;
+ struct lttng_trace_info *info;
+ sigset_t set, oldset;
+
+ /* Disable signals */
+ ret = sigfillset(&set);
+ if(ret) {
+ printf("Error in sigfillset\n");
+ exit(1);
+ }
+
+ ret = pthread_sigmask(SIG_BLOCK, &set, &oldset);
+ if(ret) {
+ printf("Error in sigprocmask\n");
+ exit(1);
+ }
/* Get all the new traces */
while(1) {
cpu_addr = fac_addr = 0;
- active = filter = 0;
- ret = ltt_update(&cpu_addr, &fac_addr, &active, &filter);
+ active = filter = destroy = 0;
+ ret = ltt_update(&cpu_addr, &fac_addr, &active, &filter, &destroy);
if(ret) {
printf("LTTng : error in ltt_update\n");
exit(1);
if(!cpu_addr || !fac_addr) break;
- first_empty = MAX_TRACES;
- /* Try to find the trace */
- for(i=0;i<MAX_TRACES;i++) {
- if(i<first_empty && !lttng_trace_info[i].channel.cpu.start)
- first_empty = i;
- if(cpu_addr ==
- (unsigned long)lttng_trace_info[i].channel.cpu.start &&
- fac_addr ==
- (unsigned long)lttng_trace_info[i].channel.facilities.start) {
-
- lttng_trace_info[i].filter = filter;
- lttng_trace_info[i].active = active;
- }
-
- }
- if(i == MAX_TRACES) {
+ info = find_info(cpu_addr, fac_addr, &first_empty);
+ if(info) {
+ info->filter = filter;
+ info->active = active;
+ info->destroy = destroy;
+ if(destroy && !atomic_read(&info->nesting))
+ lttng_free_trace_info(info);
+ } else {
/* Not found. Must take an empty slot */
if(first_empty == MAX_TRACES) {
printf(
getpid(), MAX_TRACES);
} else {
- lttng_trace_info[first_empty].channel.cpu.start = (void*)cpu_addr;
- lttng_trace_info[first_empty].channel.facilities.start =
- (void*)fac_addr;
- lttng_trace_info[first_empty].filter = filter;
- lttng_trace_info[first_empty].active = active;
+ info = <tng_trace_info[first_empty];
+ info->channel.cpu.start = (void*)cpu_addr;
+ info->channel.cpu.length = PAGE_SIZE;
+ info->channel.facilities.start = (void*)fac_addr;
+ info->channel.facilities.length = PAGE_SIZE;
+ info->filter = filter;
+ info->active = active;
+ info->destroy = destroy;
+ if(destroy && !atomic_read(&info->nesting))
+ lttng_free_trace_info(info);
}
}
}
+
+ /* Enable signals */
+ ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ if(ret) {
+ printf("Error in sigprocmask\n");
+ exit(1);
+ }
}
/* signal handler */
void __lttng_sig_trace_handler(int signo)
{
- int ret;
- sigset_t set, oldset;
-
printf("LTTng signal handler : thread id : %lu, pid %lu\n", pthread_self(), getpid());
-#if 0
- /* Disable signals */
- ret = sigfillset(&set);
- if(ret) {
- printf("Error in sigfillset\n");
- exit(1);
- }
-
- ret = sigprocmask(SIG_BLOCK, &set, &oldset);
- if(ret) {
- printf("Error in sigprocmask\n");
- exit(1);
- }
-#endif //0
-#if 0
- /* Enable signals */
- ret = sigprocmask(SIG_SETMASK, &oldset, NULL);
- if(ret) {
- printf("Error in sigprocmask\n");
- exit(1);
- }
-#endif //0
+ lttng_get_new_info();
}
static void thread_init(void)
{
- lttng_get_new_info();
int err;
+ lttng_get_new_info();
/* Make some ltt_switch syscalls */
err = ltt_switch((unsigned long)NULL);
}
-
-
-