T.c 4.69 KB
Newer Older
1 2 3 4 5 6 7 8 9
#include "T.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
Cedric Roux's avatar
Cedric Roux committed
10
#include <sys/socket.h>
11

12 13
#include "common/config/config_userapi.h"

14 15 16 17 18
#define QUIT(x) do { \
  printf("T tracer: QUIT: %s\n", x); \
  exit(1); \
} while (0)

19 20 21
/* array used to activate/disactivate a log */
static int T_IDs[T_NUMBER_OF_IDS];
int *T_active = T_IDs;
22
int T_stdout;
23 24 25 26 27 28 29 30 31

static int T_socket;

/* T_cache
 * - the T macro picks up the head of freelist and marks it busy
 * - the T sender thread periodically wakes up and sends what's to be sent
 */
volatile int _T_freelist_head;
volatile int *T_freelist_head = &_T_freelist_head;
32
T_cache_t *T_cache;
33 34 35 36 37 38

static void get_message(int s)
{
  char t;
  int l;
  int id;
Cedric Roux's avatar
Cedric Roux committed
39
  int is_on;
40

41
  if (read(s, &t, 1) != 1) QUIT("get_message fails");
Cedric Roux's avatar
Cedric Roux committed
42
printf("T tracer: got mess %d\n", t);
43 44 45 46
  switch (t) {
  case 0:
    /* toggle all those IDs */
    /* optimze? (too much syscalls) */
47
    if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
48
    while (l) {
49
      if (read(s, &id, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
50 51 52 53
      T_IDs[id] = 1 - T_IDs[id];
      l--;
    }
    break;
Cedric Roux's avatar
Cedric Roux committed
54 55 56
  case 1:
    /* set IDs as given */
    /* optimize? */
57
    if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
Cedric Roux's avatar
Cedric Roux committed
58 59
    id = 0;
    while (l) {
60 61
      if (read(s, &is_on, sizeof(int)) != sizeof(int))
        QUIT("get_message fails");
Cedric Roux's avatar
Cedric Roux committed
62 63 64 65 66
      T_IDs[id] = is_on;
      id++;
      l--;
    }
    break;
67
  case 2: break; /* do nothing, this message is to wait for local tracer */
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
  }
}

static void *T_receive_thread(void *_)
{
  while (1) get_message(T_socket);
  return NULL;
}

static void new_thread(void *(*f)(void *), void *data)
{
  pthread_t t;
  pthread_attr_t att;

  if (pthread_attr_init(&att))
    { fprintf(stderr, "pthread_attr_init err\n"); exit(1); }
  if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED))
    { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); }
  if (pthread_create(&t, &att, f, data))
    { fprintf(stderr, "pthread_create err\n"); exit(1); }
  if (pthread_attr_destroy(&att))
    { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
}

Cedric Roux's avatar
Cedric Roux committed
92 93
/* defined in local_tracer.c */
void T_local_tracer_main(int remote_port, int wait_for_tracer,
Cedric Roux's avatar
Cedric Roux committed
94
    int local_socket, char *shm_file);
Cedric Roux's avatar
Cedric Roux committed
95

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
/* We monitor the tracee and the local tracer processes.
 * When one dies we forcefully kill the other.
 */
#include <sys/types.h>
#include <sys/wait.h>
static void monitor_and_kill(int child1, int child2)
{
  int child;
  int status;

  child = wait(&status);
  if (child == -1) perror("wait");
  kill(child1, SIGKILL);
  kill(child2, SIGKILL);
  exit(0);
}

113
void T_init(int remote_port, int wait_for_tracer, int dont_fork)
114
{
Cedric Roux's avatar
Cedric Roux committed
115
  int socket_pair[2];
116 117
  int s;
  int T_shm_fd;
118
  int child1, child2;
Cedric Roux's avatar
Cedric Roux committed
119 120 121
  char shm_file[128];

  sprintf(shm_file, "/%s%d", T_SHM_FILENAME, getpid());
122

Cedric Roux's avatar
Cedric Roux committed
123 124
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
    { perror("socketpair"); abort(); }
125

126
  /* child1 runs the local tracer and child2 (or main) runs the tracee */
127 128 129

  child1 = fork(); if (child1 == -1) abort();
  if (child1 == 0) {
Cedric Roux's avatar
Cedric Roux committed
130
    close(socket_pair[1]);
Cedric Roux's avatar
Cedric Roux committed
131 132
    T_local_tracer_main(remote_port, wait_for_tracer, socket_pair[0],
                        shm_file);
Cedric Roux's avatar
Cedric Roux committed
133
    exit(0);
134
  }
Cedric Roux's avatar
Cedric Roux committed
135
  close(socket_pair[0]);
136

137 138 139 140 141 142
  if (dont_fork == 0) {
    child2 = fork(); if (child2 == -1) abort();
    if (child2 != 0) {
      close(socket_pair[1]);
      monitor_and_kill(child1, child2);
    }
143 144
  }

Cedric Roux's avatar
Cedric Roux committed
145
  s = socket_pair[1];
146 147 148 149 150 151
  /* wait for first message - initial list of active T events */
  get_message(s);

  T_socket = s;

  /* setup shared memory */
Cedric Roux's avatar
Cedric Roux committed
152 153 154
  T_shm_fd = shm_open(shm_file, O_RDWR /*| O_SYNC*/, 0666);
  shm_unlink(shm_file);
  if (T_shm_fd == -1) { perror(shm_file); abort(); }
155 156
  T_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
                 PROT_READ | PROT_WRITE, MAP_SHARED, T_shm_fd, 0);
157
  if (T_cache == MAP_FAILED)
Cedric Roux's avatar
Cedric Roux committed
158
    { perror(shm_file); abort(); }
159 160 161 162
  close(T_shm_fd);

  new_thread(T_receive_thread, NULL);
}
163 164 165 166 167 168 169 170 171

void T_Config_Init(void)
{
int T_port;            /* by default we wait for the tracer */
int T_nowait;	      /* default port to listen to to wait for the tracer */
int T_dont_fork;       /* default is to fork, see 'T_init' to understand */

paramdef_t ttraceparams[] = CMDLINE_TTRACEPARAMS_DESC ;

172 173 174 175 176
/* for a cleaner config file, TTracer params should be defined in a specific section... */
  config_get( ttraceparams,sizeof(ttraceparams)/sizeof(paramdef_t),TTRACER_CONFIG_PREFIX);

/* compatibility: look for TTracer command line options in root section */
  config_process_cmdline( ttraceparams,sizeof(ttraceparams)/sizeof(paramdef_t),NULL);
177 178 179 180 181

  if (T_stdout == 0) {
    T_init(T_port, 1-T_nowait, T_dont_fork);
  }
}