#include "unittest.h"
static size_t Bsize;
static size_t Nblock = 100;
static unsigned Seed;
static unsigned Nthread;
static unsigned Nops;
static PMEMblkpool *Handle;
static void
construct(int *ordp, unsigned char *buf)
{
for (int i = 0; i < Bsize; i++)
buf[i] = *ordp;
(*ordp)++;
if (*ordp > 255)
*ordp = 1;
}
static void
check(unsigned char *buf)
{
unsigned val = *buf;
for (int i = 1; i < Bsize; i++)
if (buf[i] != val) {
UT_OUT("{%u} TORN at byte %d", val, i);
break;
}
}
static void *
worker(void *arg)
{
long mytid = (long)(intptr_t)arg;
unsigned myseed = Seed + mytid;
unsigned char *buf = MALLOC(Bsize);
int ord = 1;
for (unsigned i = 0; i < Nops; i++) {
os_off_t lba = os_rand_r(&myseed) % Nblock;
if (os_rand_r(&myseed) % 2) {
if (pmemblk_read(Handle, buf, lba) < 0)
UT_OUT("!read lba %zu", lba);
else
check(buf);
} else {
construct(&ord, buf);
if (pmemblk_write(Handle, buf, lba) < 0)
UT_OUT("!write lba %zu", lba);
}
}
FREE(buf);
return NULL;
}
int
main(int argc, char *argv[])
{
START(argc, argv, "blk_rw_mt");
if (argc != 6)
UT_FATAL("usage: %s bsize file seed nthread nops", argv[0]);
Bsize = strtoul(argv[1], NULL, 0);
const char *path = argv[2];
if ((Handle = pmemblk_create(path, Bsize, 0,
S_IWUSR | S_IRUSR)) == NULL)
UT_FATAL("!%s: pmemblk_create", path);
if (Nblock == 0)
Nblock = pmemblk_nblock(Handle);
Seed = strtoul(argv[3], NULL, 0);
Nthread = strtoul(argv[4], NULL, 0);
Nops = strtoul(argv[5], NULL, 0);
UT_OUT("%s block size %zu usable blocks %zu", argv[1], Bsize, Nblock);
os_thread_t *threads = MALLOC(Nthread * sizeof(os_thread_t));
for (unsigned i = 0; i < Nthread; i++)
PTHREAD_CREATE(&threads[i], NULL, worker, (void *)(intptr_t)i);
for (unsigned i = 0; i < Nthread; i++)
PTHREAD_JOIN(&threads[i], NULL);
FREE(threads);
pmemblk_close(Handle);
int result = pmemblk_check(path, Bsize);
if (result < 0)
UT_OUT("!%s: pmemblk_check", path);
else if (result == 0)
UT_OUT("%s: pmemblk_check: not consistent", path);
DONE(NULL);
}