<commit_before>#define _GNU_SOURCE
#include <pthread.h>
#include <stdint.h>
#include <sched.h>
#include <signal.h>
#include <sys/timerfd.h>

#include "ringbuffer.h"
#include "protocol.h"
#include "log.h"

/* This defines the simplest 3 tests we can run, testing for 
 * tos, diffserv, & ecn awareness.
 */

#define TWD_RINGBUFFER_SIZE 4096 // 1 memory page on most systems

const char SUCCESS[] = "SUCCESS";
const char FAIL[] = "FAIL";

#define TEST_LOOPS (64 * TWD_RINGBUFFER_SIZE)

ack_t test_data_struct[TEST_LOOPS] = {0};

/* The contents of this struct are still in flux */

struct test_control {
  pthread_t thread_id; /* ID returned by pthread_create() */
  int thread_num;      /* Application-defined thread # */
  ringbuffer__s *ringbuf;

  cpu_set_t cpus;

  size_t fd;
  size_t cookie;
  size_t seqno_start;
  size_t limit;

};

typedef struct test_control test_control_t;

/* Non blocking read protected by a select call */

uint64_t read_overrun(int fd) {
  uint64_t err = 0;
  int rc = read(fd,&err,8);
  if(rc < 1) { if(errno == EAGAIN) err = 0; }
  return err;
}

/*           sigemptyset(&sigmask);
           sigaddset(&sigmask, SIGCHLD);
           if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
               perror("sigprocmask");
               exit(EXIT_FAILURE);
           }
*/

int create_timerfds(fd_set *exceptfds) {
  struct itimerspec new_value;
  struct itimerspec ms10_interval;
  struct itimerspec ms100_interval;
  struct itimerspec old_value;
  struct timespec now;
  struct timespec watchdog;
  sigset_t sigmask, empty_mask;
  struct sigaction sa;
  fd_set origfds;
  fd_set currfds;

  int rc = 0;
  int highfd = 0;
  int ms1, ms10, ms100; /* Setup timers to fire on these intervals */
  clockid_t clockid = CLOCK_MONOTONIC;
  int test = 0;
  /* When called with no flags the select only returns the first one */
  ms1 = timerfd_create(clockid,0);
  ms10 = timerfd_create(clockid,0);
  ms100 = timerfd_create(clockid,0);
  /* This needs a separate fcntl in older linuxes. Might still. Fixme.
     but it is safe presently to call this with blocking reads */

  /* ms1 = timerfd_create(clockid,TFD_NONBLOCK|TFD_CLOEXEC); */
  /* ms10 = timerfd_create(clockid,TFD_NONBLOCK|TFD_CLOEXEC); */
  /* ms100 = timerfd_create(clockid,TFD_NONBLOCK|TFD_CLOEXEC); */

  assert(ms1 > 0 || ms10 > 0 || ms100 > 0);

  if (clock_gettime(clockid, &now) == -1)
    handle_error("clock_gettime");

  watchdog.tv_sec = 5;
  watchdog.tv_nsec = 0;

  //  now.tv_sec += 1; /* start 1 sec in the future */

  new_value.it_value.tv_sec = 0; // now.tv_sec;
  new_value.it_value.tv_nsec = 1000L; // arm the timer
  new_value.it_interval.tv_sec = 0;
  new_value.it_interval.tv_nsec = 1000L * 1000L; // 1ms

  // Setting to a relative time doesn't appear to work. Perhaps
  // using TFD_TIMER_ABSTIME is better and looping til we make sure?

  if((rc = timerfd_settime(ms1, 0, &new_value, NULL)) != 0) 
  {
    printf("WTF\n");
  }

  ms10_interval.it_value.tv_sec = 0; // now.tv_sec;
  ms10_interval.it_value.tv_nsec = 1000L; // arm the timer
  ms10_interval.it_interval.tv_sec = 0;
  ms10_interval.it_interval.tv_nsec = 10L * 1000L *1000L; // 10ms
  if((rc = timerfd_settime(ms10, 0, &ms10_interval, NULL)) !=0 )
  {
    printf("WTF\n");
  }

  ms100_interval.it_value.tv_sec = 0;
  ms100_interval.it_value.tv_nsec = 1000; // arm the timer
  ms100_interval.it_interval.tv_sec = 0;
  ms100_interval.it_interval.tv_nsec = 100L * 1000L * 1000L; // 100ms
  if(( rc = timerfd_settime(ms100, 0, &ms100_interval, NULL)) !=0)
  {
    printf("WTF\n");
  }
  //  FD_ZERO(readfds);
  FD_ZERO(&origfds);
  FD_SET(ms1,&origfds);
  FD_SET(ms10,&origfds);
  FD_SET(ms100,&origfds);

  currfds = origfds;

  sigemptyset(&sigmask);
  sigfillset(&sigmask);

#define READ_OVER(f)\
  do {				 \
    if(FD_ISSET(f, &currfds))			     \
      printf( "" # f " timer fired %ld times\n", read_overrun(f)); \
  } while (0);

  printf("Starting test\n");
  highfd = ms1;
  if(ms10 > ms1) highfd = ms10; 
  if(ms100 > ms10) highfd = ms100; 
  highfd++;

  // So like, theoretically, we should get 10000 ms1, 1000 ms10, 100 ms100 
  // events...
  // FIXME Maybe we have to block signals in order to not miss an update?

  currfds = origfds;
  while(test++ < 10000 && 
	((rc = pselect(highfd,&currfds,NULL,NULL,&watchdog,&sigmask))>0))
  {
    if(rc > 0) {
    READ_OVER(ms100);
    READ_OVER(ms10);
    READ_OVER(ms1);
    rc = 0;
    }
    if (rc == -1 && errno != EINTR) {
      /* Handle error... if I wasn't blocking everything */
      printf("Got an EINTR\n");
    }
    currfds = origfds;
  }

 if(rc > 0)
    {
    READ_OVER(ms100);
    READ_OVER(ms10);
    READ_OVER(ms1);
    }
  if(rc == 0 && test < 1000) { printf("Error, watchdog fired\n"); }
  if(rc == -1) { printf("Error in select\n"); }

#undef READ_OVER
   
}

int destroy_timers() {
  return(0);
}

static void *
thread_reader(void *arg)
{
  test_control_t *tinfo = arg;
  int count;
  int seqnums = 0;
  ack_t a;
  printf("Reader started\n");
  while(!(count = ringbuffer_read(tinfo->ringbuf,&a,sizeof(a))))
    sched_yield();
  if(count != sizeof(a)) { printf("TRUNCATED READ\n"); exit(-1); }
  while(a.flags != 1) {
    //    going quiet for a test
    //    printf("Seqnum: %d; flags: %d\n", a.seqnum, a.flags);
    if (a.seqnum != seqnums) 
      printf ("missing seqno expect %d got %d\n", seqnums, a.seqnum);
    seqnums++;
    while(!(count = ringbuffer_read(tinfo->ringbuf,&a,sizeof(a))))
      sched_yield();
    if(count != sizeof(a)) { printf("TRUNCATED READ\n"); exit(-1); }
  }
  printf("Done reading!\n");
  return SUCCESS;
}

static void *
thread_writer(void *arg)
{
  test_control_t *tinfo = arg;
  int i;
  int count = 0;
  printf("Writer started\n");<commit_msg>test_simple: disarm the timers on exit<commit_after>#define _GNU_SOURCE
#include <pthread.h>
#include <stdint.h>
#include <sched.h>
#include <signal.h>
#include <sys/timerfd.h>

#include "ringbuffer.h"
#include "protocol.h"
#include "log.h"

/* This defines the simplest 3 tests we can run, testing for 
 * tos, diffserv, & ecn awareness.
 */

#define TWD_RINGBUFFER_SIZE 4096 // 1 memory page on most systems

const char SUCCESS[] = "SUCCESS";
const char FAIL[] = "FAIL";

#define TEST_LOOPS (64 * TWD_RINGBUFFER_SIZE)

ack_t test_data_struct[TEST_LOOPS] = {0};

/* The contents of this struct are still in flux */

struct test_control {
  pthread_t thread_id; /* ID returned by pthread_create() */
  int thread_num;      /* Application-defined thread # */
  ringbuffer__s *ringbuf;

  cpu_set_t cpus;

  size_t fd;
  size_t cookie;
  size_t seqno_start;
  size_t limit;

};

typedef struct test_control test_control_t;

/* Non blocking read protected by a select call */

uint64_t read_overrun(int fd) {
  uint64_t err = 0;
  int rc = read(fd,&err,8);
  if(rc < 1) { if(errno == EAGAIN) err = 0; }
  return err;
}

/*           sigemptyset(&sigmask);
           sigaddset(&sigmask, SIGCHLD);
           if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
               perror("sigprocmask");
               exit(EXIT_FAILURE);
           }
*/

int create_timerfds(fd_set *exceptfds) {
  struct itimerspec new_value;
  struct itimerspec ms10_interval;
  struct itimerspec ms100_interval;
  struct itimerspec old_value;
  struct timespec now;
  struct timespec watchdog;
  sigset_t sigmask, empty_mask;
  struct sigaction sa;
  fd_set origfds;
  fd_set currfds;

  int rc = 0;
  int highfd = 0;
  int ms1, ms10, ms100; /* Setup timers to fire on these intervals */
  clockid_t clockid = CLOCK_MONOTONIC;
  int test = 0;
  /* When called with no flags the select only returns the first one */
  ms1 = timerfd_create(clockid,0);
  ms10 = timerfd_create(clockid,0);
  ms100 = timerfd_create(clockid,0);
  /* This needs a separate fcntl in older linuxes. Might still. Fixme.
     but it is safe presently to call this with blocking reads */

  /* ms1 = timerfd_create(clockid,TFD_NONBLOCK|TFD_CLOEXEC); */
  /* ms10 = timerfd_create(clockid,TFD_NONBLOCK|TFD_CLOEXEC); */
  /* ms100 = timerfd_create(clockid,TFD_NONBLOCK|TFD_CLOEXEC); */

  assert(ms1 > 0 || ms10 > 0 || ms100 > 0);

  if (clock_gettime(clockid, &now) == -1)
    handle_error("clock_gettime");

  watchdog.tv_sec = 5;
  watchdog.tv_nsec = 0;

  //  now.tv_sec += 1; /* start 1 sec in the future */

  new_value.it_value.tv_sec = 0; // now.tv_sec;
  new_value.it_value.tv_nsec = 1000L; // arm the timer
  new_value.it_interval.tv_sec = 0;
  new_value.it_interval.tv_nsec = 1000L * 1000L; // 1ms

  // Setting to a relative time doesn't appear to work. Perhaps
  // using TFD_TIMER_ABSTIME is better and looping til we make sure?

  if((rc = timerfd_settime(ms1, 0, &new_value, NULL)) != 0) 
  {
    printf("WTF\n");
  }

  ms10_interval.it_value.tv_sec = 0; // now.tv_sec;
  ms10_interval.it_value.tv_nsec = 1000L; // arm the timer
  ms10_interval.it_interval.tv_sec = 0;
  ms10_interval.it_interval.tv_nsec = 10L * 1000L *1000L; // 10ms
  if((rc = timerfd_settime(ms10, 0, &ms10_interval, NULL)) !=0 )
  {
    printf("WTF\n");
  }

  ms100_interval.it_value.tv_sec = 0;
  ms100_interval.it_value.tv_nsec = 1000; // arm the timer
  ms100_interval.it_interval.tv_sec = 0;
  ms100_interval.it_interval.tv_nsec = 100L * 1000L * 1000L; // 100ms
  if(( rc = timerfd_settime(ms100, 0, &ms100_interval, NULL)) !=0)
  {
    printf("WTF\n");
  }
  //  FD_ZERO(readfds);
  FD_ZERO(&origfds);
  FD_SET(ms1,&origfds);
  FD_SET(ms10,&origfds);
  FD_SET(ms100,&origfds);

  currfds = origfds;

  sigemptyset(&sigmask);
  sigfillset(&sigmask);

#define READ_OVER(f)\
  do {				 \
    if(FD_ISSET(f, &currfds))			     \
      printf( "" # f " timer fired %ld times\n", read_overrun(f)); \
  } while (0);

  printf("Starting test\n");
  highfd = ms1;
  if(ms10 > ms1) highfd = ms10; 
  if(ms100 > ms10) highfd = ms100; 
  highfd++;

  // So like, theoretically, we should get 10000 ms1, 1000 ms10, 100 ms100 
  // events...
  // FIXME do we have to block signals in order to not miss an update?

  currfds = origfds;
  while(test++ < 10000 && 
	((rc = pselect(highfd,&currfds,NULL,NULL,&watchdog,&sigmask))>0))
  {
    if(rc > 0) {
    READ_OVER(ms100);
    READ_OVER(ms10);
    READ_OVER(ms1);
    rc = 0;
    }
    if (rc == -1 && errno != EINTR) {
      /* Handle error... if I wasn't blocking everything */
      printf("Got an EINTR\n");
    }
    currfds = origfds;
  }

 if(rc > 0)
    {
    READ_OVER(ms100);
    READ_OVER(ms10);
    READ_OVER(ms1);
    }
  if(rc == 0 && test < 1000) { printf("Error, watchdog fired\n"); }
  if(rc == -1) { printf("Error in select\n"); }

#undef READ_OVER

  new_value.it_value.tv_sec = 0; 
  new_value.it_value.tv_nsec = 0; // disarm the timer

  if((rc = timerfd_settime(ms1, 0, &new_value, NULL)) != 0) 
  {
    printf("Can't disarm timer\n");
  }
  if((rc = timerfd_settime(ms10, 0, &new_value, NULL)) != 0) 
  {
    printf("Can't disarm timer\n");
  }
  if((rc = timerfd_settime(ms100, 0, &new_value, NULL)) != 0) 
  {
    printf("Can't disarm timer\n");
  }
  
}

int destroy_timers() {
  return(0);
}


/* Maintain global clock shared among all threads */

static void * thread_timer(void *arg) {
	timer_t *time;
	// See above tes code for details 
        return time;
}

static void * thread_reader(void *arg)
{
  test_control_t *tinfo = arg;
  int count;
  int seqnums = 0;
  ack_t a;
  printf("Reader started\n");
  while(!(count = ringbuffer_read(tinfo->ringbuf,&a,sizeof(a))))
    sched_yield();
  if(count != sizeof(a)) { printf("TRUNCATED READ\n"); exit(-1); }
  while(a.flags != 1) {
    //    going quiet for a test
    //    printf("Seqnum: %d; flags: %d\n", a.seqnum, a.flags);
    if (a.seqnum != seqnums) 
      printf ("missing seqno expect %d got %d\n", seqnums, a.seqnum);
    seqnums++;
    while(!(count = ringbuffer_read(tinfo->ringbuf,&a,sizeof(a))))
      sched_yield();
    if(count != sizeof(a)) { printf("TRUNCATED READ\n"); exit(-1); }
  }
  printf("Done reading!\n");
  return SUCCESS;
}

static void *
thread_writer(void *arg)
{
  test_control_t *tinfo = arg;
  int i;
  int count = 0;
  printf("Writer started\n");
{'fraction_non_alphanumeric': 0.1426205068742753, 'fraction_numerical': 0.038264038429683615, 'mean_word_length': 3.248768472906404, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2793888', 'n_tokens_mistral': 5079, 'n_tokens_neox': 4622, 'n_words': 1115}