#include "terror.h"
#include <sys/mman.h>
#ifndef N_PROC
#define N_PROC 16
#endif
#define N_SLOT 12
#define N_STEP 1000
static int Pnum;
static unsigned int *Nproc;
static pid_t *Pid;
static unsigned char *Lckc;
static unsigned short *Lcks;
static unsigned int *Lcki;
static unsigned int *Done;
int lockobj(void* lck, ssize_t size, int locking)
{
int lckv, k, aso;
if(locking == 0)
{ if(size == sizeof(char))
lckv = *((char*)lck);
else if(size == sizeof(short))
lckv = *((short*)lck);
else lckv = *((int*)lck);
if(lckv != Pnum )
terror("Process %3d(pid=%d): unlocking %d(pid=%d)?",
Pnum, Pid[Pnum], lckv);
if(size == sizeof(char))
aso = asocaschar(lck, Pnum, 0);
else if(size == sizeof(short))
aso = asocasshort(lck, Pnum, 0);
else aso = asocasint(lck, Pnum, 0);
if(aso != Pnum)
terror("Process %3d(pid=%d): unlocking CAS error %d",
Pnum, Pid[Pnum], aso);
return 0;
}
for(k = 0;; ++k, usleep(100) )
{ if(size == sizeof(char))
aso = asocaschar(lck, 0, Pnum);
else if(size == sizeof(short))
aso = asocasshort(lck, 0, Pnum);
else aso = asocasint(lck, 0, Pnum);
if(aso == 0)
break;
else if(aso < 0)
terror("Process %3d(pid=%d): locking CAS error %d",
Pnum, Pid[Pnum], aso);
else if(k > 0 && (k%10000) == 0)
twarn("Process %3d(pid=%d): locking loop %d blocked by %d",
Pnum, Pid[Pnum], k, aso);
}
for(k = 0; k < 2; ++k, usleep(100) )
{ if(size == sizeof(char))
lckv = *((char*)lck);
else if(size == sizeof(short))
lckv = *((short*)lck);
else lckv = *((int*)lck);
if(lckv != Pnum)
terror("Process %3d(pid=%d): at step %d lock=%d?",
Pnum, Pid[Pnum], k, lckv);
}
return 0;
}
static void workload(int pnum)
{
int k, r;
Pnum = pnum;
for(k = 0; k < N_STEP; ++k)
{ if(k > 0 && (k%100) == 0)
tinfo("Process %3d(pid=%d): progress to %d", Pnum, Pid[Pnum], k);
r = random()%N_SLOT;
lockobj(Lcki+r, sizeof(int), 1);
if(Lcki[r] != Pnum)
terror("Process %3d(pid=%d): bad int lock %d",
Pnum, Pid[Pnum], (int)Lcki[r]);
lockobj(Lcki+r, sizeof(int), 0);
r = random()%N_SLOT;
lockobj(Lcks+r, sizeof(short), 1);
if(Lcks[r] != Pnum)
terror("Process %3d(pid=%d): bad short lock %d",
Pnum, Pid[Pnum], (int)Lcks[r]);
lockobj(Lcks+r, sizeof(short), 0);
r = random()%N_SLOT;
lockobj(Lckc+r, sizeof(char), 1);
if(Lckc[r] != Pnum)
terror("Process %3d(pid=%d): bad char lock %d",
Pnum, Pid[Pnum], (int)Lckc[r]);
lockobj(Lckc+r, sizeof(char), 0);
}
asoincint(Done);
}
tmain()
{
ssize_t k, z;
Void_t *addr;
int zerof;
pid_t pid;
taso(ASO_PROCESS);
if (!Tstall && !(asometh(0, 0)->type & ASO_INTRINSIC))
{
twarn("only ASO_INTRINSIC methods are tested by default");
texit(0);
}
tchild();
if((zerof = open("/dev/zero", O_RDWR)) < 0)
terror("Can't open /dev/zero");
z = sizeof(*Nproc) + (N_PROC+1)*sizeof(pid_t) + sizeof(*Done) +
N_SLOT*sizeof(unsigned char) +
N_SLOT*sizeof(unsigned short) +
N_SLOT*sizeof(unsigned int);
addr = mmap(0,z,PROT_READ|PROT_WRITE,MAP_SHARED,zerof,0);
if(!addr || addr == (Void_t*)(-1))
terror("mmap failed");
memset(addr, 0, z);
Nproc = (unsigned int*)addr;
Pid = (pid_t*)(Nproc+1);
Done = (unsigned int*)(Pid + (N_PROC+1)*sizeof(pid_t));
Lcki = (unsigned int*)(Done + 1);
Lcks = (unsigned short*)(Lcki + N_SLOT);
Lckc = (unsigned char* )(Lcks + N_SLOT);
for(k = 1; k <= N_PROC; ++k)
{ if((pid = fork()) < 0 )
terror("Can't create a child process");
else if(pid > 0 )
{ Pid[k] = pid; *Nproc += 1;
continue;
}
else
{ for(;; usleep(1000) )
if(*Nproc == N_PROC)
break;
workload(k);
texit(0);
}
}
if (twait(Pid+1, N_PROC))
terror("workload subprocess error");
if(*Done != N_PROC)
terror("Some subprocess did not finish its workload");
texit(0);
}