/* DF-4478 variant B: 4 setstate walkers (alternating states) + 2 attach/detach */
#include <sys/types.h>
#include <sys/ioccom.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE 1024
#define VINUM_CREATE _IOC(IOC_INOUT, 'F', 64, BUFSIZE)
#define VINUM_SETSTATE _IOC(IOC_INOUT, 'F', 76, 256)
#define VINUM_ATTACH _IOC(IOC_INOUT, 'F', 87, 260)
#define VINUM_DETACH _IOC(IOC_INOUT, 'F', 88, 260)
enum { sd_object=1, plex_object=2 };
struct m { int index,type,state,op,force,recurse,verify,otherobject,rename; long long offset; int blocksize; };
static int fd; static volatile int stop;
static volatile unsigned long nss,nat,ndt;
static void line(const char*l){char b[BUFSIZE];memset(b,0,sizeof b);snprintf(b,sizeof b,"%s",l);ioctl(fd,VINUM_CREATE,b);}
static void *t_ss(void *a){char b[256];struct m*m=(struct m*)b;int which=(int)(size_t)a;
  while(!stop){memset(b,0,sizeof b);m->index=0;m->type=plex_object;m->force=1;
    m->state=(which&1)?3:0; /* alternate object_up / object_down */
    if(ioctl(fd,VINUM_SETSTATE,b)==0)nss++;}
  return NULL;}
static void *t_ad(void *a){char b[268];struct m*m=(struct m*)b;(void)a;
  while(!stop){memset(b,0,sizeof b);m->index=0;m->type=sd_object;m->otherobject=0;m->force=1;
    if(ioctl(fd,VINUM_ATTACH,b)==0)nat++;
    memset(b,0,sizeof b);m->index=0;m->type=sd_object;m->force=1;
    if(ioctl(fd,VINUM_DETACH,b)==0)ndt++;}
  return NULL;}
int main(int argc,char**argv){pthread_t t[8];time_t t0=time(NULL),limit=argc>1?atoi(argv[1]):180;int i;
  fd=open("/dev/vinum/control",O_RDWR);if(fd<0){perror("open");return 1;}
  line("plex name p0 org concat");
  line("sd name s0 drive d0 len 2048s driveoffset 0s");
  printf("racing (up/down alternation) for %lds\n",(long)limit);
  for(i=0;i<4;i++)pthread_create(&t[i],NULL,t_ss,(void*)(size_t)i);
  for(i=4;i<6;i++)pthread_create(&t[i],NULL,t_ad,NULL);
  while(time(NULL)-t0<limit){sleep(5);printf("ss=%lu at=%lu dt=%lu\n",nss,nat,ndt);}
  stop=1;for(i=0;i<6;i++)pthread_join(t[i],NULL);
  printf("SURVIVED ss=%lu at=%lu dt=%lu\n",nss,nat,ndt);return 0;}
