clang-format
This commit is contained in:
@@ -39,19 +39,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, j;
|
||||
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: add num1 num2");
|
||||
}
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: add num1 num2");
|
||||
}
|
||||
|
||||
i = atoi(argv[1]);
|
||||
j = atoi(argv[2]);
|
||||
i = atoi(argv[1]);
|
||||
j = atoi(argv[2]);
|
||||
|
||||
printf("Answer: %d\n", i+j);
|
||||
printf("Answer: %d\n", i + j);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,21 +37,19 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *tmp;
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *tmp;
|
||||
int i;
|
||||
|
||||
printf("argc: %d\n", argc);
|
||||
printf("argc: %d\n", argc);
|
||||
|
||||
for (i=0; i<=argc; i++) {
|
||||
tmp = argv[i];
|
||||
if (tmp==NULL) {
|
||||
tmp = "[NULL]";
|
||||
}
|
||||
printf("argv[%d]: %s\n", i, tmp);
|
||||
}
|
||||
for (i = 0; i <= argc; i++) {
|
||||
tmp = argv[i];
|
||||
if (tmp == NULL) {
|
||||
tmp = "[NULL]";
|
||||
}
|
||||
printf("argv[%d]: %s\n", i, tmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,25 +37,19 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
chdir_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void chdir_empty(void) {
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* This is actually valid by some interpretations.
|
||||
*/
|
||||
/*
|
||||
* This is actually valid by some interpretations.
|
||||
*/
|
||||
|
||||
report_begin("chdir to empty string");
|
||||
rv = chdir("");
|
||||
report_check2(rv, errno, EINVAL, 0);
|
||||
report_begin("chdir to empty string");
|
||||
rv = chdir("");
|
||||
report_check2(rv, errno, EINVAL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
test_chdir(void)
|
||||
{
|
||||
test_chdir_path();
|
||||
chdir_empty();
|
||||
void test_chdir(void) {
|
||||
test_chdir_path();
|
||||
chdir_empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,4 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_close(void)
|
||||
{
|
||||
test_close_fd();
|
||||
}
|
||||
void test_close(void) { test_close_fd(); }
|
||||
|
||||
@@ -44,99 +44,86 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
dup2_fd2(int fd, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void dup2_fd2(int fd, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = dup2(STDIN_FILENO, fd);
|
||||
report_check(rv, errno, EBADF);
|
||||
report_begin("%s", desc);
|
||||
rv = dup2(STDIN_FILENO, fd);
|
||||
report_check(rv, errno, EBADF);
|
||||
|
||||
if (rv != -1) {
|
||||
close(fd); /* just in case */
|
||||
}
|
||||
if (rv != -1) {
|
||||
close(fd); /* just in case */
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dup2_self(void)
|
||||
{
|
||||
struct stat sb;
|
||||
int rv;
|
||||
int testfd;
|
||||
static void dup2_self(void) {
|
||||
struct stat sb;
|
||||
int rv;
|
||||
int testfd;
|
||||
|
||||
/* use fd that isn't in use */
|
||||
testfd = CLOSED_FD;
|
||||
/* use fd that isn't in use */
|
||||
testfd = CLOSED_FD;
|
||||
|
||||
report_begin("copying stdin to test with");
|
||||
report_begin("copying stdin to test with");
|
||||
|
||||
rv = dup2(STDIN_FILENO, testfd);
|
||||
if (rv == -1) {
|
||||
report_result(rv, errno);
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
rv = dup2(STDIN_FILENO, testfd);
|
||||
if (rv == -1) {
|
||||
report_result(rv, errno);
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin("dup2 to same fd");
|
||||
rv = dup2(testfd, testfd);
|
||||
if (rv == testfd) {
|
||||
report_passed();
|
||||
}
|
||||
else if (rv<0) {
|
||||
report_result(rv, errno);
|
||||
report_failure();
|
||||
}
|
||||
else {
|
||||
report_warnx("returned %d instead", rv);
|
||||
report_failure();
|
||||
}
|
||||
report_begin("dup2 to same fd");
|
||||
rv = dup2(testfd, testfd);
|
||||
if (rv == testfd) {
|
||||
report_passed();
|
||||
} else if (rv < 0) {
|
||||
report_result(rv, errno);
|
||||
report_failure();
|
||||
} else {
|
||||
report_warnx("returned %d instead", rv);
|
||||
report_failure();
|
||||
}
|
||||
|
||||
report_begin("fstat fd after dup2 to itself");
|
||||
rv = fstat(testfd, &sb);
|
||||
if (errno == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_result(rv, errno);
|
||||
if (rv==0) {
|
||||
report_passed();
|
||||
}
|
||||
else if (errno != ENOSYS) {
|
||||
report_failure();
|
||||
}
|
||||
else {
|
||||
report_skipped();
|
||||
/* no support for fstat; try lseek */
|
||||
report_begin("lseek fd after dup2 to itself");
|
||||
rv = lseek(testfd, 0, SEEK_CUR);
|
||||
report_result(rv, errno);
|
||||
if (rv==0 || (rv==-1 && errno==ESPIPE)) {
|
||||
report_passed();
|
||||
}
|
||||
else {
|
||||
report_failure();
|
||||
}
|
||||
}
|
||||
report_begin("fstat fd after dup2 to itself");
|
||||
rv = fstat(testfd, &sb);
|
||||
if (errno == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_result(rv, errno);
|
||||
if (rv == 0) {
|
||||
report_passed();
|
||||
} else if (errno != ENOSYS) {
|
||||
report_failure();
|
||||
} else {
|
||||
report_skipped();
|
||||
/* no support for fstat; try lseek */
|
||||
report_begin("lseek fd after dup2 to itself");
|
||||
rv = lseek(testfd, 0, SEEK_CUR);
|
||||
report_result(rv, errno);
|
||||
if (rv == 0 || (rv == -1 && errno == ESPIPE)) {
|
||||
report_passed();
|
||||
} else {
|
||||
report_failure();
|
||||
}
|
||||
}
|
||||
|
||||
close(testfd);
|
||||
close(testfd);
|
||||
}
|
||||
|
||||
void
|
||||
test_dup2(void)
|
||||
{
|
||||
/* This does the first fd. */
|
||||
test_dup2_fd();
|
||||
void test_dup2(void) {
|
||||
/* This does the first fd. */
|
||||
test_dup2_fd();
|
||||
|
||||
/* Any interesting cases added here should also go in common_fds.c */
|
||||
dup2_fd2(-1, "dup2 to -1");
|
||||
dup2_fd2(-5, "dup2 to -5");
|
||||
dup2_fd2(IMPOSSIBLE_FD, "dup2 to impossible fd");
|
||||
/* Any interesting cases added here should also go in common_fds.c */
|
||||
dup2_fd2(-1, "dup2 to -1");
|
||||
dup2_fd2(-5, "dup2 to -5");
|
||||
dup2_fd2(IMPOSSIBLE_FD, "dup2 to impossible fd");
|
||||
#ifdef OPEN_MAX
|
||||
dup2_fd2(OPEN_MAX, "dup2 to OPEN_MAX");
|
||||
dup2_fd2(OPEN_MAX, "dup2 to OPEN_MAX");
|
||||
#else
|
||||
warnx("Warning: OPEN_MAX not defined - test skipped");
|
||||
warnx("Warning: OPEN_MAX not defined - test skipped");
|
||||
#endif
|
||||
|
||||
dup2_self();
|
||||
dup2_self();
|
||||
}
|
||||
|
||||
@@ -40,142 +40,124 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
int
|
||||
exec_common_fork(void)
|
||||
{
|
||||
int pid, rv, status, err;
|
||||
static int exec_common_fork(void) {
|
||||
int pid, rv, status, err;
|
||||
|
||||
/*
|
||||
* This does not happen in a test context (from the point of
|
||||
* view of report.c) so we have to fiddle a bit.
|
||||
*/
|
||||
/*
|
||||
* This does not happen in a test context (from the point of
|
||||
* view of report.c) so we have to fiddle a bit.
|
||||
*/
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
err = errno;
|
||||
report_begin("forking for test");
|
||||
report_result(pid, err);
|
||||
report_aborted();
|
||||
return -1;
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
err = errno;
|
||||
report_begin("forking for test");
|
||||
report_result(pid, err);
|
||||
report_aborted();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid==0) {
|
||||
/* child */
|
||||
return 0;
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv == -1) {
|
||||
err = errno;
|
||||
report_begin("waiting for test subprocess");
|
||||
report_result(rv, err);
|
||||
report_failure();
|
||||
return -1;
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == MAGIC_STATUS) {
|
||||
return 1;
|
||||
}
|
||||
/* Oops... */
|
||||
report_begin("exit code of subprocess; should be %d", MAGIC_STATUS);
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("signal %d", WTERMSIG(status));
|
||||
}
|
||||
else {
|
||||
report_warnx("exit %d", WEXITSTATUS(status));
|
||||
}
|
||||
report_failure();
|
||||
return -1;
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv == -1) {
|
||||
err = errno;
|
||||
report_begin("waiting for test subprocess");
|
||||
report_result(rv, err);
|
||||
report_failure();
|
||||
return -1;
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == MAGIC_STATUS) {
|
||||
return 1;
|
||||
}
|
||||
/* Oops... */
|
||||
report_begin("exit code of subprocess; should be %d", MAGIC_STATUS);
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("signal %d", WTERMSIG(status));
|
||||
} else {
|
||||
report_warnx("exit %d", WEXITSTATUS(status));
|
||||
}
|
||||
report_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_badprog(const void *prog, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
static void exec_badprog(const void *prog, const char *desc) {
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin(desc);
|
||||
rv = execv(prog, args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin(desc);
|
||||
rv = execv(prog, args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_emptyprog(void)
|
||||
{
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
static void exec_emptyprog(void) {
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin("exec the empty string");
|
||||
rv = execv("", args);
|
||||
report_check2(rv, errno, EINVAL, EISDIR);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin("exec the empty string");
|
||||
rv = execv("", args);
|
||||
report_check2(rv, errno, EINVAL, EISDIR);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_badargs(void *args, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void exec_badargs(void *args, const char *desc) {
|
||||
int rv;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_onearg(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void exec_onearg(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
char *args[3];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = (char *)ptr;
|
||||
args[2] = NULL;
|
||||
char *args[3];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = (char *)ptr;
|
||||
args[2] = NULL;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
void
|
||||
test_execv(void)
|
||||
{
|
||||
exec_badprog(NULL, "exec with NULL program");
|
||||
exec_badprog(INVAL_PTR, "exec with invalid pointer program");
|
||||
exec_badprog(KERN_PTR, "exec with kernel pointer program");
|
||||
void test_execv(void) {
|
||||
exec_badprog(NULL, "exec with NULL program");
|
||||
exec_badprog(INVAL_PTR, "exec with invalid pointer program");
|
||||
exec_badprog(KERN_PTR, "exec with kernel pointer program");
|
||||
|
||||
exec_emptyprog();
|
||||
exec_emptyprog();
|
||||
|
||||
exec_badargs(NULL, "exec with NULL arglist");
|
||||
exec_badargs(INVAL_PTR, "exec with invalid pointer arglist");
|
||||
exec_badargs(KERN_PTR, "exec with kernel pointer arglist");
|
||||
exec_badargs(NULL, "exec with NULL arglist");
|
||||
exec_badargs(INVAL_PTR, "exec with invalid pointer arglist");
|
||||
exec_badargs(KERN_PTR, "exec with kernel pointer arglist");
|
||||
|
||||
exec_onearg(INVAL_PTR, "exec with invalid pointer arg");
|
||||
exec_onearg(KERN_PTR, "exec with kernel pointer arg");
|
||||
exec_onearg(INVAL_PTR, "exec with invalid pointer arg");
|
||||
exec_onearg(KERN_PTR, "exec with kernel pointer arg");
|
||||
}
|
||||
|
||||
@@ -33,9 +33,4 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_fsync(void)
|
||||
{
|
||||
test_fsync_fd();
|
||||
}
|
||||
|
||||
void test_fsync(void) { test_fsync_fd(); }
|
||||
|
||||
@@ -43,53 +43,45 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
ftruncate_fd_device(void)
|
||||
{
|
||||
int rv, fd;
|
||||
static void ftruncate_fd_device(void) {
|
||||
int rv, fd;
|
||||
|
||||
report_begin("ftruncate on device");
|
||||
report_begin("ftruncate on device");
|
||||
|
||||
fd = open("null:", O_RDWR);
|
||||
if (fd<0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open("null:", O_RDWR);
|
||||
if (fd < 0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = ftruncate(fd, 6);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = ftruncate(fd, 6);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ftruncate_size_neg(void)
|
||||
{
|
||||
int rv, fd;
|
||||
static void ftruncate_size_neg(void) {
|
||||
int rv, fd;
|
||||
|
||||
report_begin("ftruncate to negative size");
|
||||
report_begin("ftruncate to negative size");
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = ftruncate(fd, -60);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = ftruncate(fd, -60);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
void
|
||||
test_ftruncate(void)
|
||||
{
|
||||
test_ftruncate_fd();
|
||||
void test_ftruncate(void) {
|
||||
test_ftruncate_fd();
|
||||
|
||||
ftruncate_fd_device();
|
||||
ftruncate_size_neg();
|
||||
ftruncate_fd_device();
|
||||
ftruncate_size_neg();
|
||||
}
|
||||
|
||||
@@ -33,8 +33,4 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_getcwd(void)
|
||||
{
|
||||
test_getcwd_buf();
|
||||
}
|
||||
void test_getcwd(void) { test_getcwd_buf(); }
|
||||
|
||||
@@ -33,9 +33,7 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_getdirentry(void)
|
||||
{
|
||||
test_getdirentry_fd();
|
||||
test_getdirentry_buf();
|
||||
void test_getdirentry(void) {
|
||||
test_getdirentry_fd();
|
||||
test_getdirentry_buf();
|
||||
}
|
||||
|
||||
@@ -40,64 +40,49 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
one_ioctl_badbuf(int fd, int code, const char *codename,
|
||||
void *ptr, const char *ptrdesc)
|
||||
{
|
||||
int rv;
|
||||
static void one_ioctl_badbuf(int fd, int code, const char *codename, void *ptr,
|
||||
const char *ptrdesc) {
|
||||
int rv;
|
||||
|
||||
report_begin("ioctl %s with %s", codename, ptrdesc);
|
||||
rv = ioctl(fd, code, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("ioctl %s with %s", codename, ptrdesc);
|
||||
rv = ioctl(fd, code, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
any_ioctl_badbuf(int fd, int code, const char *codename)
|
||||
{
|
||||
one_ioctl_badbuf(fd, code, codename, NULL, "NULL pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, INVAL_PTR, "invalid pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, KERN_PTR, "kernel pointer");
|
||||
static void any_ioctl_badbuf(int fd, int code, const char *codename) {
|
||||
one_ioctl_badbuf(fd, code, codename, NULL, "NULL pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, INVAL_PTR, "invalid pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, KERN_PTR, "kernel pointer");
|
||||
}
|
||||
|
||||
#define IOCTL(fd, sym) any_ioctl_badbuf(fd, sym, #sym)
|
||||
|
||||
static
|
||||
void
|
||||
ioctl_badbuf(void)
|
||||
{
|
||||
/*
|
||||
* Since we don't actually define any ioctls, this code won't
|
||||
* actually run. But if you do define ioctls, turn these tests
|
||||
* on for those that actually use the data buffer argument for
|
||||
* anything.
|
||||
*/
|
||||
static void ioctl_badbuf(void) {
|
||||
/*
|
||||
* Since we don't actually define any ioctls, this code won't
|
||||
* actually run. But if you do define ioctls, turn these tests
|
||||
* on for those that actually use the data buffer argument for
|
||||
* anything.
|
||||
*/
|
||||
|
||||
/* IOCTL(STDIN_FILENO, TIOCGETA); */
|
||||
/* IOCTL(STDIN_FILENO, TIOCGETA); */
|
||||
|
||||
|
||||
/* suppress gcc warning */
|
||||
(void)any_ioctl_badbuf;
|
||||
/* suppress gcc warning */
|
||||
(void)any_ioctl_badbuf;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ioctl_badcode(void)
|
||||
{
|
||||
int rv;
|
||||
static void ioctl_badcode(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("invalid ioctl");
|
||||
rv = ioctl(STDIN_FILENO, NONEXIST_IOCTL, NULL);
|
||||
report_check(rv, errno, EIOCTL);
|
||||
report_begin("invalid ioctl");
|
||||
rv = ioctl(STDIN_FILENO, NONEXIST_IOCTL, NULL);
|
||||
report_check(rv, errno, EIOCTL);
|
||||
}
|
||||
|
||||
void
|
||||
test_ioctl(void)
|
||||
{
|
||||
test_ioctl_fd();
|
||||
void test_ioctl(void) {
|
||||
test_ioctl_fd();
|
||||
|
||||
/* Since we don't actually define any ioctls, this is not meaningful */
|
||||
ioctl_badcode();
|
||||
ioctl_badbuf();
|
||||
/* Since we don't actually define any ioctls, this is not meaningful */
|
||||
ioctl_badcode();
|
||||
ioctl_badbuf();
|
||||
}
|
||||
|
||||
@@ -36,53 +36,42 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
link_dir(void)
|
||||
{
|
||||
int rv;
|
||||
static void link_dir(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("hard link of .");
|
||||
rv = link(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv==0) {
|
||||
/* this might help recover... maybe */
|
||||
remove(TESTDIR);
|
||||
}
|
||||
report_begin("hard link of .");
|
||||
rv = link(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* this might help recover... maybe */
|
||||
remove(TESTDIR);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
link_empty1(void)
|
||||
{
|
||||
int rv;
|
||||
static void link_empty1(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("hard link of empty string");
|
||||
rv = link("", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("hard link of empty string");
|
||||
rv = link("", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
link_empty2(void)
|
||||
{
|
||||
int rv;
|
||||
static void link_empty2(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("hard link to empty string");
|
||||
if (create_testdir()<0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = link(TESTDIR, "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
report_begin("hard link to empty string");
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = link(TESTDIR, "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
void
|
||||
test_link(void)
|
||||
{
|
||||
test_link_paths();
|
||||
link_dir();
|
||||
link_empty1();
|
||||
link_empty2();
|
||||
void test_link(void) {
|
||||
test_link_paths();
|
||||
link_dir();
|
||||
link_empty1();
|
||||
link_empty2();
|
||||
}
|
||||
|
||||
@@ -43,236 +43,213 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
lseek_fd_device(void)
|
||||
{
|
||||
int fd, rv;
|
||||
static void lseek_fd_device(void) {
|
||||
int fd, rv;
|
||||
|
||||
report_begin("lseek on device");
|
||||
report_begin("lseek on device");
|
||||
|
||||
fd = open("null:", O_RDONLY);
|
||||
if (fd<0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open("null:", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = lseek(fd, 309, SEEK_SET);
|
||||
report_check(rv, errno, ESPIPE);
|
||||
rv = lseek(fd, 309, SEEK_SET);
|
||||
report_check(rv, errno, ESPIPE);
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_file_stdin(void)
|
||||
{
|
||||
int fd, fd2, rv, status;
|
||||
const char slogan[] = "There ain't no such thing as a free lunch";
|
||||
size_t len = strlen(slogan);
|
||||
pid_t pid;
|
||||
static void lseek_file_stdin(void) {
|
||||
int fd, fd2, rv, status;
|
||||
const char slogan[] = "There ain't no such thing as a free lunch";
|
||||
size_t len = strlen(slogan);
|
||||
pid_t pid;
|
||||
|
||||
report_begin("lseek stdin when open on file");
|
||||
report_begin("lseek stdin when open on file");
|
||||
|
||||
/* fork so we don't affect our own stdin */
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
else if (pid!=0) {
|
||||
/* parent */
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv<0) {
|
||||
report_warn("waitpid failed");
|
||||
report_aborted();
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("subprocess exited with signal %d",
|
||||
WTERMSIG(status));
|
||||
report_aborted();
|
||||
}
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
report_warnx("subprocess exited with code %d",
|
||||
WEXITSTATUS(status));
|
||||
report_aborted();
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* fork so we don't affect our own stdin */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
} else if (pid != 0) {
|
||||
/* parent */
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv < 0) {
|
||||
report_warn("waitpid failed");
|
||||
report_aborted();
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("subprocess exited with signal %d", WTERMSIG(status));
|
||||
report_aborted();
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
report_warnx("subprocess exited with code %d", WEXITSTATUS(status));
|
||||
report_aborted();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* child */
|
||||
/* child */
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
_exit(0);
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move file to stdin.
|
||||
* Use stdin (rather than stdout or stderr) to maximize the
|
||||
* chances of detecting any special-case handling of fds 0-2.
|
||||
* (Writing to stdin is fine as long as it's open for write,
|
||||
* and it will be.)
|
||||
*/
|
||||
fd2 = dup2(fd, STDIN_FILENO);
|
||||
if (fd2<0) {
|
||||
report_warn("dup2 to stdin failed");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
if (fd2 != STDIN_FILENO) {
|
||||
report_warn("dup2 returned wrong file handle");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
close(fd);
|
||||
/*
|
||||
* Move file to stdin.
|
||||
* Use stdin (rather than stdout or stderr) to maximize the
|
||||
* chances of detecting any special-case handling of fds 0-2.
|
||||
* (Writing to stdin is fine as long as it's open for write,
|
||||
* and it will be.)
|
||||
*/
|
||||
fd2 = dup2(fd, STDIN_FILENO);
|
||||
if (fd2 < 0) {
|
||||
report_warn("dup2 to stdin failed");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
if (fd2 != STDIN_FILENO) {
|
||||
report_warn("dup2 returned wrong file handle");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
rv = write(STDIN_FILENO, slogan, len);
|
||||
if (rv<0) {
|
||||
report_warn("write to %s (via stdin) failed", TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
rv = write(STDIN_FILENO, slogan, len);
|
||||
if (rv < 0) {
|
||||
report_warn("write to %s (via stdin) failed", TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if ((unsigned)rv != len) {
|
||||
report_warnx("write to %s (via stdin) got short count",
|
||||
TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
if ((unsigned)rv != len) {
|
||||
report_warnx("write to %s (via stdin) got short count", TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* blah */
|
||||
report_skipped();
|
||||
/* blah */
|
||||
report_skipped();
|
||||
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_SET);
|
||||
report_begin("try 1: SEEK_SET");
|
||||
report_check(rv, errno, 0);
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_SET);
|
||||
report_begin("try 1: SEEK_SET");
|
||||
report_check(rv, errno, 0);
|
||||
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_END);
|
||||
report_begin("try 2: SEEK_END");
|
||||
report_check(rv, errno, 0);
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_END);
|
||||
report_begin("try 2: SEEK_END");
|
||||
report_check(rv, errno, 0);
|
||||
|
||||
remove(TESTFILE);
|
||||
_exit(0);
|
||||
remove(TESTFILE);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_loc_negative(void)
|
||||
{
|
||||
int fd, rv;
|
||||
static void lseek_loc_negative(void) {
|
||||
int fd, rv;
|
||||
|
||||
report_begin("lseek to negative offset");
|
||||
report_begin("lseek to negative offset");
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = lseek(fd, -309, SEEK_SET);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = lseek(fd, -309, SEEK_SET);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_whence_inval(void)
|
||||
{
|
||||
int fd, rv;
|
||||
static void lseek_whence_inval(void) {
|
||||
int fd, rv;
|
||||
|
||||
report_begin("lseek with invalid whence code");
|
||||
report_begin("lseek with invalid whence code");
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = lseek(fd, 0, 3594);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = lseek(fd, 0, 3594);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_loc_pasteof(void)
|
||||
{
|
||||
const char *message = "blahblah";
|
||||
int fd;
|
||||
off_t pos;
|
||||
static void lseek_loc_pasteof(void) {
|
||||
const char *message = "blahblah";
|
||||
int fd;
|
||||
off_t pos;
|
||||
|
||||
report_begin("seek past/to EOF");
|
||||
report_begin("seek past/to EOF");
|
||||
|
||||
fd = open_testfile(message);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(message);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
pos = lseek(fd, 5340, SEEK_SET);
|
||||
if (pos == -1) {
|
||||
report_warn("lseek past EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5340) {
|
||||
report_warnx("lseek to 5340 got offset %lld", (long long) pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
pos = lseek(fd, 5340, SEEK_SET);
|
||||
if (pos == -1) {
|
||||
report_warn("lseek past EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5340) {
|
||||
report_warnx("lseek to 5340 got offset %lld", (long long)pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos = lseek(fd, -50, SEEK_CUR);
|
||||
if (pos == -1) {
|
||||
report_warn("small seek beyond EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5290) {
|
||||
report_warnx("SEEK_CUR to 5290 got offset %lld",
|
||||
(long long) pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
pos = lseek(fd, -50, SEEK_CUR);
|
||||
if (pos == -1) {
|
||||
report_warn("small seek beyond EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5290) {
|
||||
report_warnx("SEEK_CUR to 5290 got offset %lld", (long long)pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos = lseek(fd, 0, SEEK_END);
|
||||
if (pos == -1) {
|
||||
report_warn("seek to EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
pos = lseek(fd, 0, SEEK_END);
|
||||
if (pos == -1) {
|
||||
report_warn("seek to EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pos != (off_t) strlen(message)) {
|
||||
report_warnx("seek to EOF got %lld (should be %zu)",
|
||||
(long long) pos, strlen(message));
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != (off_t)strlen(message)) {
|
||||
report_warnx("seek to EOF got %lld (should be %zu)", (long long)pos,
|
||||
strlen(message));
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
report_passed();
|
||||
report_passed();
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return;
|
||||
out:
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
test_lseek(void)
|
||||
{
|
||||
test_lseek_fd();
|
||||
void test_lseek(void) {
|
||||
test_lseek_fd();
|
||||
|
||||
lseek_fd_device();
|
||||
lseek_file_stdin();
|
||||
lseek_loc_negative();
|
||||
lseek_loc_pasteof();
|
||||
lseek_whence_inval();
|
||||
lseek_fd_device();
|
||||
lseek_file_stdin();
|
||||
lseek_loc_negative();
|
||||
lseek_loc_pasteof();
|
||||
lseek_whence_inval();
|
||||
}
|
||||
|
||||
@@ -43,45 +43,34 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
mkdir_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void mkdir_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("mkdir .");
|
||||
rv = mkdir(".", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
report_begin("mkdir .");
|
||||
rv = mkdir(".", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mkdir_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void mkdir_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("mkdir ..");
|
||||
rv = mkdir("..", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
report_begin("mkdir ..");
|
||||
rv = mkdir("..", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mkdir_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void mkdir_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("mkdir of empty string");
|
||||
rv = mkdir("", 0775);
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("mkdir of empty string");
|
||||
rv = mkdir("", 0775);
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_mkdir(void)
|
||||
{
|
||||
test_mkdir_path();
|
||||
void test_mkdir(void) {
|
||||
test_mkdir_path();
|
||||
|
||||
mkdir_dot();
|
||||
mkdir_dotdot();
|
||||
mkdir_empty();
|
||||
mkdir_dot();
|
||||
mkdir_dotdot();
|
||||
mkdir_empty();
|
||||
}
|
||||
|
||||
@@ -43,36 +43,28 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
open_badflags(void)
|
||||
{
|
||||
int fd;
|
||||
static void open_badflags(void) {
|
||||
int fd;
|
||||
|
||||
report_begin("open null: with bad flags");
|
||||
fd = open("null:", 309842);
|
||||
report_check(fd, errno, EINVAL);
|
||||
report_begin("open null: with bad flags");
|
||||
fd = open("null:", 309842);
|
||||
report_check(fd, errno, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
open_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void open_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("open empty string");
|
||||
rv = open("", O_RDONLY);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv>=0) {
|
||||
close(rv);
|
||||
}
|
||||
report_begin("open empty string");
|
||||
rv = open("", O_RDONLY);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv >= 0) {
|
||||
close(rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_open(void)
|
||||
{
|
||||
test_open_path();
|
||||
void test_open(void) {
|
||||
test_open_path();
|
||||
|
||||
open_badflags();
|
||||
open_empty();
|
||||
open_badflags();
|
||||
open_empty();
|
||||
}
|
||||
|
||||
@@ -43,44 +43,36 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
pipe_badptr(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void pipe_badptr(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = pipe(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("%s", desc);
|
||||
rv = pipe(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
pipe_unaligned(void)
|
||||
{
|
||||
int fds[3], rv;
|
||||
char *ptr;
|
||||
static void pipe_unaligned(void) {
|
||||
int fds[3], rv;
|
||||
char *ptr;
|
||||
|
||||
report_begin("pipe with unaligned pointer");
|
||||
report_begin("pipe with unaligned pointer");
|
||||
|
||||
ptr = (char *)&fds[0];
|
||||
ptr++;
|
||||
ptr = (char *)&fds[0];
|
||||
ptr++;
|
||||
|
||||
rv = pipe((int *)ptr);
|
||||
report_survival(rv, errno);
|
||||
if (rv == 0) {
|
||||
memmove(fds, ptr, 2*sizeof(int));
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
}
|
||||
rv = pipe((int *)ptr);
|
||||
report_survival(rv, errno);
|
||||
if (rv == 0) {
|
||||
memmove(fds, ptr, 2 * sizeof(int));
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_pipe(void)
|
||||
{
|
||||
pipe_badptr(NULL, "pipe with NULL pointer");
|
||||
pipe_badptr(INVAL_PTR, "pipe with invalid pointer");
|
||||
pipe_badptr(KERN_PTR, "pipe with kernel pointer");
|
||||
void test_pipe(void) {
|
||||
pipe_badptr(NULL, "pipe with NULL pointer");
|
||||
pipe_badptr(INVAL_PTR, "pipe with invalid pointer");
|
||||
pipe_badptr(KERN_PTR, "pipe with kernel pointer");
|
||||
|
||||
pipe_unaligned();
|
||||
pipe_unaligned();
|
||||
}
|
||||
|
||||
@@ -33,10 +33,7 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_read(void)
|
||||
{
|
||||
test_read_fd();
|
||||
test_read_buf();
|
||||
void test_read(void) {
|
||||
test_read_fd();
|
||||
test_read_buf();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,57 +36,45 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
readlink_file(void)
|
||||
{
|
||||
char buf[128];
|
||||
int fd, rv;
|
||||
static void readlink_file(void) {
|
||||
char buf[128];
|
||||
int fd, rv;
|
||||
|
||||
report_begin("readlink on file");
|
||||
fd = open_testfile("the question contains an invalid assumption");
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
rv = readlink(TESTFILE, buf, sizeof(buf));
|
||||
report_check(rv, errno, EINVAL);
|
||||
remove(TESTFILE);
|
||||
report_begin("readlink on file");
|
||||
fd = open_testfile("the question contains an invalid assumption");
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
rv = readlink(TESTFILE, buf, sizeof(buf));
|
||||
report_check(rv, errno, EINVAL);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readlink_dir(void)
|
||||
{
|
||||
char buf[128];
|
||||
int rv;
|
||||
static void readlink_dir(void) {
|
||||
char buf[128];
|
||||
int rv;
|
||||
|
||||
report_begin("readlink on .");
|
||||
rv = readlink(".", buf, sizeof(buf));
|
||||
report_check(rv, errno, EISDIR);
|
||||
report_begin("readlink on .");
|
||||
rv = readlink(".", buf, sizeof(buf));
|
||||
report_check(rv, errno, EISDIR);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readlink_empty(void)
|
||||
{
|
||||
char buf[128];
|
||||
int rv;
|
||||
static void readlink_empty(void) {
|
||||
char buf[128];
|
||||
int rv;
|
||||
|
||||
report_begin("readlink on empty string");
|
||||
rv = readlink("", buf, sizeof(buf));
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("readlink on empty string");
|
||||
rv = readlink("", buf, sizeof(buf));
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_readlink(void)
|
||||
{
|
||||
test_readlink_path();
|
||||
test_readlink_buf();
|
||||
void test_readlink(void) {
|
||||
test_readlink_path();
|
||||
test_readlink_buf();
|
||||
|
||||
readlink_file();
|
||||
readlink_dir();
|
||||
readlink_empty();
|
||||
readlink_file();
|
||||
readlink_dir();
|
||||
readlink_empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,20 +43,13 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
reboot_badflags(void)
|
||||
{
|
||||
int rv;
|
||||
static void reboot_badflags(void) {
|
||||
int rv;
|
||||
|
||||
printf("(This should not kill the system...)\n");
|
||||
report_begin("reboot with invalid flags");
|
||||
rv = reboot(15353);
|
||||
report_check(rv, errno, EINVAL);
|
||||
printf("(This should not kill the system...)\n");
|
||||
report_begin("reboot with invalid flags");
|
||||
rv = reboot(15353);
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_reboot(void)
|
||||
{
|
||||
reboot_badflags();
|
||||
}
|
||||
void test_reboot(void) { reboot_badflags(); }
|
||||
|
||||
@@ -43,64 +43,50 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
remove_dir(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_dir(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on a directory");
|
||||
report_begin("remove() on a directory");
|
||||
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
|
||||
rv = remove(TESTDIR);
|
||||
report_check(rv, errno, EISDIR);
|
||||
rmdir(TESTDIR);
|
||||
rv = remove(TESTDIR);
|
||||
report_check(rv, errno, EISDIR);
|
||||
rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
remove_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on .");
|
||||
rv = remove(".");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("remove() on .");
|
||||
rv = remove(".");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
remove_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on ..");
|
||||
rv = remove("..");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("remove() on ..");
|
||||
rv = remove("..");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
remove_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on empty string");
|
||||
rv = remove("");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("remove() on empty string");
|
||||
rv = remove("");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_remove(void)
|
||||
{
|
||||
test_remove_path();
|
||||
void test_remove(void) {
|
||||
test_remove_path();
|
||||
|
||||
remove_dir();
|
||||
remove_dot();
|
||||
remove_dotdot();
|
||||
remove_empty();
|
||||
remove_dir();
|
||||
remove_dot();
|
||||
remove_dotdot();
|
||||
remove_empty();
|
||||
}
|
||||
|
||||
@@ -36,76 +36,61 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
rename_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename .");
|
||||
report_begin("rename .");
|
||||
|
||||
rv = rename(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv==0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, ".");
|
||||
}
|
||||
rv = rename(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, ".");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rename_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename ..");
|
||||
rv = rename("..", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv==0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, "..");
|
||||
}
|
||||
report_begin("rename ..");
|
||||
rv = rename("..", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, "..");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rename_empty1(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_empty1(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename empty string");
|
||||
rv = rename("", TESTDIR);
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
if (rv==0) {
|
||||
/* don't try to remove it */
|
||||
rename(TESTDIR, TESTDIR "-foo");
|
||||
}
|
||||
report_begin("rename empty string");
|
||||
rv = rename("", TESTDIR);
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* don't try to remove it */
|
||||
rename(TESTDIR, TESTDIR "-foo");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rename_empty2(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_empty2(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename to empty string");
|
||||
if (create_testdir()<0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = rename(TESTDIR, "");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
report_begin("rename to empty string");
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = rename(TESTDIR, "");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
void
|
||||
test_rename(void)
|
||||
{
|
||||
test_rename_paths();
|
||||
void test_rename(void) {
|
||||
test_rename_paths();
|
||||
|
||||
rename_dot();
|
||||
rename_dotdot();
|
||||
rename_empty1();
|
||||
rename_empty2();
|
||||
rename_dot();
|
||||
rename_dotdot();
|
||||
rename_empty1();
|
||||
rename_empty2();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,62 +43,48 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_file(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_file(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir a file");
|
||||
if (create_testfile()<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
rv = rmdir(TESTFILE);
|
||||
report_check(rv, errno, ENOTDIR);
|
||||
remove(TESTFILE);
|
||||
report_begin("rmdir a file");
|
||||
if (create_testfile() < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
rv = rmdir(TESTFILE);
|
||||
report_check(rv, errno, ENOTDIR);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir .");
|
||||
rv = rmdir(".");
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("rmdir .");
|
||||
rv = rmdir(".");
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir ..");
|
||||
rv = rmdir("..");
|
||||
report_check2(rv, errno, EINVAL, ENOTEMPTY);
|
||||
report_begin("rmdir ..");
|
||||
rv = rmdir("..");
|
||||
report_check2(rv, errno, EINVAL, ENOTEMPTY);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir empty string");
|
||||
rv = rmdir("");
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("rmdir empty string");
|
||||
rv = rmdir("");
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_rmdir(void)
|
||||
{
|
||||
test_rmdir_path();
|
||||
void test_rmdir(void) {
|
||||
test_rmdir_path();
|
||||
|
||||
rmdir_file();
|
||||
rmdir_dot();
|
||||
rmdir_dotdot();
|
||||
rmdir_empty();
|
||||
rmdir_file();
|
||||
rmdir_dot();
|
||||
rmdir_dotdot();
|
||||
rmdir_empty();
|
||||
}
|
||||
|
||||
@@ -46,80 +46,56 @@
|
||||
/*
|
||||
* typing wrapper around sbrk
|
||||
*/
|
||||
static
|
||||
int
|
||||
try_sbrk(long val)
|
||||
{
|
||||
void *rv;
|
||||
rv = sbrk(val);
|
||||
if (rv==(void *)-1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
static int try_sbrk(long val) {
|
||||
void *rv;
|
||||
rv = sbrk(val);
|
||||
if (rv == (void *)-1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
enforce_sbrk(long val, const char *desc, int err)
|
||||
{
|
||||
int result;
|
||||
static void enforce_sbrk(long val, const char *desc, int err) {
|
||||
int result;
|
||||
|
||||
report_begin("sbrk %s", desc);
|
||||
report_begin("sbrk %s", desc);
|
||||
|
||||
result = try_sbrk(val);
|
||||
report_check(result, errno, err);
|
||||
result = try_sbrk(val);
|
||||
report_check(result, errno, err);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_bigpos(void)
|
||||
{
|
||||
enforce_sbrk(4096*1024*256, "huge positive", ENOMEM);
|
||||
static void sbrk_bigpos(void) {
|
||||
enforce_sbrk(4096 * 1024 * 256, "huge positive", ENOMEM);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_bigneg(void)
|
||||
{
|
||||
enforce_sbrk(-4096*1024*256, "huge negative", EINVAL);
|
||||
static void sbrk_bigneg(void) {
|
||||
enforce_sbrk(-4096 * 1024 * 256, "huge negative", EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_neg(void)
|
||||
{
|
||||
enforce_sbrk(-8192, "too-large negative", EINVAL);
|
||||
static void sbrk_neg(void) {
|
||||
enforce_sbrk(-8192, "too-large negative", EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_unalignedpos(void)
|
||||
{
|
||||
int result;
|
||||
static void sbrk_unalignedpos(void) {
|
||||
int result;
|
||||
|
||||
report_begin("sbrk unaligned positive");
|
||||
result = try_sbrk(17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
report_begin("sbrk unaligned positive");
|
||||
result = try_sbrk(17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_unalignedneg(void)
|
||||
{
|
||||
int result;
|
||||
static void sbrk_unalignedneg(void) {
|
||||
int result;
|
||||
|
||||
report_begin("sbrk unaligned negative");
|
||||
result = try_sbrk(-17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
report_begin("sbrk unaligned negative");
|
||||
result = try_sbrk(-17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_sbrk(void)
|
||||
{
|
||||
sbrk_neg();
|
||||
sbrk_bigpos();
|
||||
sbrk_bigneg();
|
||||
sbrk_unalignedpos();
|
||||
sbrk_unalignedneg();
|
||||
void test_sbrk(void) {
|
||||
sbrk_neg();
|
||||
sbrk_bigpos();
|
||||
sbrk_bigneg();
|
||||
sbrk_unalignedpos();
|
||||
sbrk_unalignedneg();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,84 +45,54 @@
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
int
|
||||
badbuf_fstat(struct stat *sb)
|
||||
{
|
||||
return fstat(STDIN_FILENO, sb);
|
||||
static int badbuf_fstat(struct stat *sb) { return fstat(STDIN_FILENO, sb); }
|
||||
|
||||
static int badbuf_lstat(struct stat *sb) { return lstat("null:", sb); }
|
||||
|
||||
static int badbuf_stat(struct stat *sb) { return stat("null:", sb); }
|
||||
|
||||
static void common_badbuf(int (*statfunc)(struct stat *), void *ptr,
|
||||
const char *call, const char *ptrdesc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s with %s buf", call, ptrdesc);
|
||||
rv = statfunc(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
badbuf_lstat(struct stat *sb)
|
||||
{
|
||||
return lstat("null:", sb);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
badbuf_stat(struct stat *sb)
|
||||
{
|
||||
return stat("null:", sb);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
common_badbuf(int (*statfunc)(struct stat *), void *ptr,
|
||||
const char *call, const char *ptrdesc)
|
||||
{
|
||||
int rv;
|
||||
|
||||
report_begin("%s with %s buf", call, ptrdesc);
|
||||
rv = statfunc(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
any_badbuf(int (*statfunc)(struct stat *), const char *call)
|
||||
{
|
||||
common_badbuf(statfunc, NULL, call, "NULL");
|
||||
common_badbuf(statfunc, INVAL_PTR, call, "invalid pointer");
|
||||
common_badbuf(statfunc, KERN_PTR, call, "kernel pointer");
|
||||
static void any_badbuf(int (*statfunc)(struct stat *), const char *call) {
|
||||
common_badbuf(statfunc, NULL, call, "NULL");
|
||||
common_badbuf(statfunc, INVAL_PTR, call, "invalid pointer");
|
||||
common_badbuf(statfunc, KERN_PTR, call, "kernel pointer");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
any_empty(int (*statfunc)(const char *, struct stat *), const char *call)
|
||||
{
|
||||
struct stat sb;
|
||||
int rv;
|
||||
static void any_empty(int (*statfunc)(const char *, struct stat *),
|
||||
const char *call) {
|
||||
struct stat sb;
|
||||
int rv;
|
||||
|
||||
report_begin("%s on empty string", call);
|
||||
rv = statfunc("", &sb);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
report_begin("%s on empty string", call);
|
||||
rv = statfunc("", &sb);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
test_fstat(void)
|
||||
{
|
||||
test_fstat_fd();
|
||||
any_badbuf(badbuf_fstat, "fstat");
|
||||
void test_fstat(void) {
|
||||
test_fstat_fd();
|
||||
any_badbuf(badbuf_fstat, "fstat");
|
||||
}
|
||||
|
||||
void
|
||||
test_lstat(void)
|
||||
{
|
||||
test_lstat_path();
|
||||
any_empty(lstat, "lstat");
|
||||
any_badbuf(badbuf_lstat, "lstat");
|
||||
void test_lstat(void) {
|
||||
test_lstat_path();
|
||||
any_empty(lstat, "lstat");
|
||||
any_badbuf(badbuf_lstat, "lstat");
|
||||
}
|
||||
|
||||
void
|
||||
test_stat(void)
|
||||
{
|
||||
test_stat_path();
|
||||
any_empty(stat, "stat");
|
||||
any_badbuf(badbuf_stat, "stat");
|
||||
void test_stat(void) {
|
||||
test_stat_path();
|
||||
any_empty(stat, "stat");
|
||||
any_badbuf(badbuf_stat, "stat");
|
||||
}
|
||||
|
||||
|
||||
@@ -36,33 +36,25 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
symlink_empty1(void)
|
||||
{
|
||||
int rv;
|
||||
static void symlink_empty1(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("symlink -> empty string");
|
||||
rv = symlink("", TESTLINK);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
remove(TESTLINK);
|
||||
report_begin("symlink -> empty string");
|
||||
rv = symlink("", TESTLINK);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
remove(TESTLINK);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
symlink_empty2(void)
|
||||
{
|
||||
int rv;
|
||||
static void symlink_empty2(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("symlink named empty string");
|
||||
rv = symlink("foo", "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("symlink named empty string");
|
||||
rv = symlink("foo", "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_symlink(void)
|
||||
{
|
||||
test_symlink_paths();
|
||||
symlink_empty1();
|
||||
symlink_empty2();
|
||||
void test_symlink(void) {
|
||||
test_symlink_paths();
|
||||
symlink_empty1();
|
||||
symlink_empty2();
|
||||
}
|
||||
|
||||
@@ -43,34 +43,26 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
time_badsecs(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void time_badsecs(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = __time(ptr, NULL);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("%s", desc);
|
||||
rv = __time(ptr, NULL);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
time_badnsecs(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void time_badnsecs(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = __time(NULL, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("%s", desc);
|
||||
rv = __time(NULL, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
void
|
||||
test_time(void)
|
||||
{
|
||||
time_badsecs(INVAL_PTR, "__time with invalid seconds pointer");
|
||||
time_badsecs(KERN_PTR, "__time with kernel seconds pointer");
|
||||
void test_time(void) {
|
||||
time_badsecs(INVAL_PTR, "__time with invalid seconds pointer");
|
||||
time_badsecs(KERN_PTR, "__time with kernel seconds pointer");
|
||||
|
||||
time_badnsecs(INVAL_PTR, "__time with invalid nsecs pointer");
|
||||
time_badnsecs(KERN_PTR, "__time with kernel nsecs pointer");
|
||||
time_badnsecs(INVAL_PTR, "__time with invalid nsecs pointer");
|
||||
time_badnsecs(KERN_PTR, "__time with kernel nsecs pointer");
|
||||
}
|
||||
|
||||
@@ -41,383 +41,344 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
wait_badpid(pid_t pid, const char *desc)
|
||||
{
|
||||
pid_t rv;
|
||||
int x;
|
||||
int err;
|
||||
static void wait_badpid(pid_t pid, const char *desc) {
|
||||
pid_t rv;
|
||||
int x;
|
||||
int err;
|
||||
|
||||
report_begin(desc);
|
||||
rv = waitpid(pid, &x, 0);
|
||||
err = errno;
|
||||
/* Allow ENOSYS for 0 or negative values of pid only */
|
||||
if (pid <= 0 && rv == -1 && err == ENOSYS) {
|
||||
err = ESRCH;
|
||||
}
|
||||
else if (err == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_check2(rv, err, ESRCH, ECHILD);
|
||||
report_begin(desc);
|
||||
rv = waitpid(pid, &x, 0);
|
||||
err = errno;
|
||||
/* Allow ENOSYS for 0 or negative values of pid only */
|
||||
if (pid <= 0 && rv == -1 && err == ENOSYS) {
|
||||
err = ESRCH;
|
||||
} else if (err == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_check2(rv, err, ESRCH, ECHILD);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_nullstatus(void)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
static void wait_nullstatus(void) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait with NULL status");
|
||||
report_begin("wait with NULL status");
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* POSIX explicitly says passing NULL for status is allowed */
|
||||
rv = waitpid(pid, NULL, 0);
|
||||
report_check(rv, errno, 0);
|
||||
waitpid(pid, &x, 0);
|
||||
/* POSIX explicitly says passing NULL for status is allowed */
|
||||
rv = waitpid(pid, NULL, 0);
|
||||
report_check(rv, errno, 0);
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_badstatus(void *ptr, const char *desc)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
static void wait_badstatus(void *ptr, const char *desc) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
|
||||
report_begin(desc);
|
||||
report_begin(desc);
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
rv = waitpid(pid, ptr, 0);
|
||||
report_check(rv, errno, EFAULT);
|
||||
waitpid(pid, &x, 0);
|
||||
rv = waitpid(pid, ptr, 0);
|
||||
report_check(rv, errno, EFAULT);
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_unaligned(void)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
int status[2]; /* will have integer alignment */
|
||||
char *ptr;
|
||||
static void wait_unaligned(void) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
int status[2]; /* will have integer alignment */
|
||||
char *ptr;
|
||||
|
||||
report_begin("wait with unaligned status");
|
||||
report_begin("wait with unaligned status");
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* start with proper integer alignment */
|
||||
ptr = (char *)(&status[0]);
|
||||
/* start with proper integer alignment */
|
||||
ptr = (char *)(&status[0]);
|
||||
|
||||
/* generate improper alignment on platforms with restrictions */
|
||||
ptr++;
|
||||
/* generate improper alignment on platforms with restrictions */
|
||||
ptr++;
|
||||
|
||||
rv = waitpid(pid, (int *)ptr, 0);
|
||||
report_survival(rv, errno);
|
||||
if (rv<0) {
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
rv = waitpid(pid, (int *)ptr, 0);
|
||||
report_survival(rv, errno);
|
||||
if (rv < 0) {
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_badflags(void)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
static void wait_badflags(void) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait with bad flags");
|
||||
report_begin("wait with bad flags");
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
rv = waitpid(pid, &x, 309429);
|
||||
report_check(rv, errno, EINVAL);
|
||||
waitpid(pid, &x, 0);
|
||||
rv = waitpid(pid, &x, 309429);
|
||||
report_check(rv, errno, EINVAL);
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_self(void)
|
||||
{
|
||||
pid_t rv;
|
||||
int x;
|
||||
static void wait_self(void) {
|
||||
pid_t rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait for self");
|
||||
report_begin("wait for self");
|
||||
|
||||
rv = waitpid(getpid(), &x, 0);
|
||||
report_survival(rv, errno);
|
||||
rv = waitpid(getpid(), &x, 0);
|
||||
report_survival(rv, errno);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_parent(void)
|
||||
{
|
||||
pid_t mypid, childpid, rv;
|
||||
int x;
|
||||
static void wait_parent(void) {
|
||||
pid_t mypid, childpid, rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait for parent");
|
||||
report_hassubs();
|
||||
report_begin("wait for parent");
|
||||
report_hassubs();
|
||||
|
||||
mypid = getpid();
|
||||
childpid = fork();
|
||||
if (childpid<0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (childpid==0) {
|
||||
/* Child. Wait for parent. */
|
||||
rv = waitpid(mypid, &x, 0);
|
||||
report_beginsub("from child:");
|
||||
report_survival(rv, errno);
|
||||
_exit(0);
|
||||
}
|
||||
rv = waitpid(childpid, &x, 0);
|
||||
report_beginsub("from parent:");
|
||||
report_survival(rv, errno);
|
||||
mypid = getpid();
|
||||
childpid = fork();
|
||||
if (childpid < 0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (childpid == 0) {
|
||||
/* Child. Wait for parent. */
|
||||
rv = waitpid(mypid, &x, 0);
|
||||
report_beginsub("from child:");
|
||||
report_survival(rv, errno);
|
||||
_exit(0);
|
||||
}
|
||||
rv = waitpid(childpid, &x, 0);
|
||||
report_beginsub("from parent:");
|
||||
report_survival(rv, errno);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
wait_siblings_child(const char *semname)
|
||||
{
|
||||
pid_t pids[2], mypid, otherpid;
|
||||
int rv, fd, semfd, x;
|
||||
char c;
|
||||
static void wait_siblings_child(const char *semname) {
|
||||
pid_t pids[2], mypid, otherpid;
|
||||
int rv, fd, semfd, x;
|
||||
char c;
|
||||
|
||||
mypid = getpid();
|
||||
mypid = getpid();
|
||||
|
||||
/*
|
||||
* Get our own handle for the semaphore, in case naive
|
||||
* file-level synchronization causes concurrent use to
|
||||
* deadlock.
|
||||
*/
|
||||
semfd = open(semname, O_RDONLY);
|
||||
if (semfd < 0) {
|
||||
report_warn("child process (pid %d) can't open %s",
|
||||
mypid, semname);
|
||||
}
|
||||
else {
|
||||
if (read(semfd, &c, 1) < 0) {
|
||||
report_warn("in pid %d: %s: read", mypid, semname);
|
||||
}
|
||||
close(semfd);
|
||||
}
|
||||
/*
|
||||
* Get our own handle for the semaphore, in case naive
|
||||
* file-level synchronization causes concurrent use to
|
||||
* deadlock.
|
||||
*/
|
||||
semfd = open(semname, O_RDONLY);
|
||||
if (semfd < 0) {
|
||||
report_warn("child process (pid %d) can't open %s", mypid, semname);
|
||||
} else {
|
||||
if (read(semfd, &c, 1) < 0) {
|
||||
report_warn("in pid %d: %s: read", mypid, semname);
|
||||
}
|
||||
close(semfd);
|
||||
}
|
||||
|
||||
fd = open(TESTFILE, O_RDONLY);
|
||||
if (fd<0) {
|
||||
report_warn("child process (pid %d) can't open %s",
|
||||
mypid, TESTFILE);
|
||||
return;
|
||||
}
|
||||
fd = open(TESTFILE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
report_warn("child process (pid %d) can't open %s", mypid, TESTFILE);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case the semaphore above didn't work, as a backup
|
||||
* busy-wait until the parent writes the pids into the
|
||||
* file. If the semaphore did work, this shouldn't loop.
|
||||
*/
|
||||
do {
|
||||
rv = lseek(fd, 0, SEEK_SET);
|
||||
if (rv<0) {
|
||||
report_warn("child process (pid %d) lseek error",
|
||||
mypid);
|
||||
return;
|
||||
}
|
||||
rv = read(fd, pids, sizeof(pids));
|
||||
if (rv<0) {
|
||||
report_warn("child process (pid %d) read error",
|
||||
mypid);
|
||||
return;
|
||||
}
|
||||
} while (rv < (int)sizeof(pids));
|
||||
/*
|
||||
* In case the semaphore above didn't work, as a backup
|
||||
* busy-wait until the parent writes the pids into the
|
||||
* file. If the semaphore did work, this shouldn't loop.
|
||||
*/
|
||||
do {
|
||||
rv = lseek(fd, 0, SEEK_SET);
|
||||
if (rv < 0) {
|
||||
report_warn("child process (pid %d) lseek error", mypid);
|
||||
return;
|
||||
}
|
||||
rv = read(fd, pids, sizeof(pids));
|
||||
if (rv < 0) {
|
||||
report_warn("child process (pid %d) read error", mypid);
|
||||
return;
|
||||
}
|
||||
} while (rv < (int)sizeof(pids));
|
||||
|
||||
if (mypid==pids[0]) {
|
||||
otherpid = pids[1];
|
||||
}
|
||||
else if (mypid==pids[1]) {
|
||||
otherpid = pids[0];
|
||||
}
|
||||
else {
|
||||
report_warn("child process (pid %d) got garbage in comm file",
|
||||
mypid);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
if (mypid == pids[0]) {
|
||||
otherpid = pids[1];
|
||||
} else if (mypid == pids[1]) {
|
||||
otherpid = pids[0];
|
||||
} else {
|
||||
report_warn("child process (pid %d) got garbage in comm file", mypid);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
rv = waitpid(otherpid, &x, 0);
|
||||
report_beginsub("sibling (pid %d)", mypid);
|
||||
report_survival(rv, errno);
|
||||
rv = waitpid(otherpid, &x, 0);
|
||||
report_beginsub("sibling (pid %d)", mypid);
|
||||
report_survival(rv, errno);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_siblings(void)
|
||||
{
|
||||
pid_t pids[2];
|
||||
int rv, fd, semfd, x;
|
||||
int bad = 0;
|
||||
char semname[32];
|
||||
static void wait_siblings(void) {
|
||||
pid_t pids[2];
|
||||
int rv, fd, semfd, x;
|
||||
int bad = 0;
|
||||
char semname[32];
|
||||
|
||||
/* This test may also blow up if FS synchronization is substandard */
|
||||
/* This test may also blow up if FS synchronization is substandard */
|
||||
|
||||
report_begin("siblings wait for each other");
|
||||
report_hassubs();
|
||||
report_begin("siblings wait for each other");
|
||||
report_hassubs();
|
||||
|
||||
snprintf(semname, sizeof(semname), "sem:badcall.%d", (int)getpid());
|
||||
semfd = open(semname, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (semfd < 0) {
|
||||
report_warn("can't make semaphore");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
snprintf(semname, sizeof(semname), "sem:badcall.%d", (int)getpid());
|
||||
semfd = open(semname, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (semfd < 0) {
|
||||
report_warn("can't make semaphore");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
|
||||
pids[0] = fork();
|
||||
if (pids[0]<0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[0]==0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
pids[0] = fork();
|
||||
if (pids[0] < 0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[0] == 0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
pids[1] = fork();
|
||||
if (pids[1]<0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
/* abandon the other child process :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[1]==0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
pids[1] = fork();
|
||||
if (pids[1] < 0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
/* abandon the other child process :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[1] == 0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
rv = write(fd, pids, sizeof(pids));
|
||||
if (rv < 0) {
|
||||
report_warn("write error on %s", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (rv != (int)sizeof(pids)) {
|
||||
report_warnx("write error on %s: short count", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
rv = write(fd, pids, sizeof(pids));
|
||||
if (rv < 0) {
|
||||
report_warn("write error on %s", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (rv != (int)sizeof(pids)) {
|
||||
report_warnx("write error on %s: short count", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* gate the child procs */
|
||||
rv = write(semfd, " ", 2);
|
||||
if (rv < 0) {
|
||||
report_warn("%s: write", semname);
|
||||
bad = 1;
|
||||
}
|
||||
/* gate the child procs */
|
||||
rv = write(semfd, " ", 2);
|
||||
if (rv < 0) {
|
||||
report_warn("%s: write", semname);
|
||||
bad = 1;
|
||||
}
|
||||
|
||||
report_beginsub("overall");
|
||||
rv = waitpid(pids[0], &x, 0);
|
||||
if (rv<0) {
|
||||
report_warn("error waiting for child 0 (pid %d)", pids[0]);
|
||||
bad = 1;
|
||||
}
|
||||
rv = waitpid(pids[1], &x, 0);
|
||||
if (rv<0) {
|
||||
report_warn("error waiting for child 1 (pid %d)", pids[1]);
|
||||
bad = 1;
|
||||
}
|
||||
if (bad) {
|
||||
/* XXX: aborted, or failure, or what? */
|
||||
report_aborted();
|
||||
}
|
||||
else {
|
||||
report_passed();
|
||||
}
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
remove(TESTFILE);
|
||||
report_beginsub("overall");
|
||||
rv = waitpid(pids[0], &x, 0);
|
||||
if (rv < 0) {
|
||||
report_warn("error waiting for child 0 (pid %d)", pids[0]);
|
||||
bad = 1;
|
||||
}
|
||||
rv = waitpid(pids[1], &x, 0);
|
||||
if (rv < 0) {
|
||||
report_warn("error waiting for child 1 (pid %d)", pids[1]);
|
||||
bad = 1;
|
||||
}
|
||||
if (bad) {
|
||||
/* XXX: aborted, or failure, or what? */
|
||||
report_aborted();
|
||||
} else {
|
||||
report_passed();
|
||||
}
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
test_waitpid(void)
|
||||
{
|
||||
wait_badpid(-8, "wait for pid -8");
|
||||
wait_badpid(-1, "wait for pid -1");
|
||||
wait_badpid(0, "pid zero");
|
||||
wait_badpid(NONEXIST_PID, "nonexistent pid");
|
||||
void test_waitpid(void) {
|
||||
wait_badpid(-8, "wait for pid -8");
|
||||
wait_badpid(-1, "wait for pid -1");
|
||||
wait_badpid(0, "pid zero");
|
||||
wait_badpid(NONEXIST_PID, "nonexistent pid");
|
||||
|
||||
wait_nullstatus();
|
||||
wait_badstatus(INVAL_PTR, "wait with invalid pointer status");
|
||||
wait_badstatus(KERN_PTR, "wait with kernel pointer status");
|
||||
wait_nullstatus();
|
||||
wait_badstatus(INVAL_PTR, "wait with invalid pointer status");
|
||||
wait_badstatus(KERN_PTR, "wait with kernel pointer status");
|
||||
|
||||
wait_unaligned();
|
||||
wait_unaligned();
|
||||
|
||||
wait_badflags();
|
||||
wait_badflags();
|
||||
|
||||
wait_self();
|
||||
wait_parent();
|
||||
wait_siblings();
|
||||
wait_self();
|
||||
wait_parent();
|
||||
wait_siblings();
|
||||
}
|
||||
|
||||
@@ -33,9 +33,7 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_write(void)
|
||||
{
|
||||
test_write_fd();
|
||||
test_write_buf();
|
||||
void test_write(void) {
|
||||
test_write_fd();
|
||||
test_write_buf();
|
||||
}
|
||||
|
||||
@@ -47,169 +47,108 @@
|
||||
static int buf_fd;
|
||||
|
||||
struct buftest {
|
||||
int (*setup)(void);
|
||||
int (*op)(void *);
|
||||
void (*cleanup)(void);
|
||||
const char *name;
|
||||
int (*setup)(void);
|
||||
int (*op)(void *);
|
||||
void (*cleanup)(void);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
int
|
||||
read_setup(void)
|
||||
{
|
||||
buf_fd = open_testfile("i do not like green eggs and ham");
|
||||
if (buf_fd<0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
static int read_setup(void) {
|
||||
buf_fd = open_testfile("i do not like green eggs and ham");
|
||||
if (buf_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
read_badbuf(void *buf)
|
||||
{
|
||||
return read(buf_fd, buf, 128);
|
||||
}
|
||||
static int read_badbuf(void *buf) { return read(buf_fd, buf, 128); }
|
||||
|
||||
static
|
||||
void
|
||||
read_cleanup(void)
|
||||
{
|
||||
close(buf_fd);
|
||||
remove(TESTFILE);
|
||||
static void read_cleanup(void) {
|
||||
close(buf_fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
static
|
||||
int
|
||||
write_setup(void)
|
||||
{
|
||||
buf_fd = open_testfile(NULL);
|
||||
if (buf_fd<0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
static int write_setup(void) {
|
||||
buf_fd = open_testfile(NULL);
|
||||
if (buf_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
write_badbuf(void *ptr)
|
||||
{
|
||||
return write(buf_fd, ptr, 128);
|
||||
}
|
||||
static int write_badbuf(void *ptr) { return write(buf_fd, ptr, 128); }
|
||||
|
||||
static
|
||||
void
|
||||
write_cleanup(void)
|
||||
{
|
||||
close(buf_fd);
|
||||
remove(TESTFILE);
|
||||
static void write_cleanup(void) {
|
||||
close(buf_fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
static
|
||||
int
|
||||
getdirentry_setup(void)
|
||||
{
|
||||
buf_fd = open(".", O_RDONLY);
|
||||
if (buf_fd < 0) {
|
||||
warn("UH-OH: couldn't open .");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
static int getdirentry_setup(void) {
|
||||
buf_fd = open(".", O_RDONLY);
|
||||
if (buf_fd < 0) {
|
||||
warn("UH-OH: couldn't open .");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
getdirentry_badbuf(void *ptr)
|
||||
{
|
||||
return getdirentry(buf_fd, ptr, 1024);
|
||||
static int getdirentry_badbuf(void *ptr) {
|
||||
return getdirentry(buf_fd, ptr, 1024);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getdirentry_cleanup(void)
|
||||
{
|
||||
close(buf_fd);
|
||||
}
|
||||
static void getdirentry_cleanup(void) { close(buf_fd); }
|
||||
|
||||
//////////
|
||||
|
||||
static
|
||||
int
|
||||
readlink_setup(void)
|
||||
{
|
||||
return create_testlink();
|
||||
}
|
||||
static int readlink_setup(void) { return create_testlink(); }
|
||||
|
||||
static
|
||||
int
|
||||
readlink_badbuf(void *buf)
|
||||
{
|
||||
return readlink(TESTLINK, buf, 168);
|
||||
}
|
||||
static int readlink_badbuf(void *buf) { return readlink(TESTLINK, buf, 168); }
|
||||
|
||||
static
|
||||
void
|
||||
readlink_cleanup(void)
|
||||
{
|
||||
remove(TESTLINK);
|
||||
}
|
||||
static void readlink_cleanup(void) { remove(TESTLINK); }
|
||||
|
||||
//////////
|
||||
|
||||
static int getcwd_setup(void) { return 0; }
|
||||
static void getcwd_cleanup(void) {}
|
||||
|
||||
static
|
||||
int
|
||||
getcwd_badbuf(void *buf)
|
||||
{
|
||||
return __getcwd(buf, 408);
|
||||
static int getcwd_badbuf(void *buf) { return __getcwd(buf, 408); }
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static void common_badbuf(struct buftest *info, void *buf,
|
||||
const char *bufdesc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s with %s buffer", info->name, bufdesc);
|
||||
info->setup();
|
||||
rv = info->op(buf);
|
||||
report_check(rv, errno, EFAULT);
|
||||
info->cleanup();
|
||||
}
|
||||
|
||||
static void any_badbuf(struct buftest *info) {
|
||||
common_badbuf(info, NULL, "NULL");
|
||||
common_badbuf(info, INVAL_PTR, "invalid");
|
||||
common_badbuf(info, KERN_PTR, "kernel-space");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
common_badbuf(struct buftest *info, void *buf, const char *bufdesc)
|
||||
{
|
||||
int rv;
|
||||
|
||||
|
||||
report_begin("%s with %s buffer", info->name, bufdesc);
|
||||
info->setup();
|
||||
rv = info->op(buf);
|
||||
report_check(rv, errno, EFAULT);
|
||||
info->cleanup();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
any_badbuf(struct buftest *info)
|
||||
{
|
||||
common_badbuf(info, NULL, "NULL");
|
||||
common_badbuf(info, INVAL_PTR, "invalid");
|
||||
common_badbuf(info, KERN_PTR, "kernel-space");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#define T(call) \
|
||||
void \
|
||||
test_##call##_buf(void) \
|
||||
{ \
|
||||
static struct buftest info = { \
|
||||
call##_setup, \
|
||||
call##_badbuf, \
|
||||
call##_cleanup, \
|
||||
#call, \
|
||||
}; \
|
||||
any_badbuf(&info); \
|
||||
#define T(call) \
|
||||
void test_##call##_buf(void) { \
|
||||
static struct buftest info = { \
|
||||
call##_setup, \
|
||||
call##_badbuf, \
|
||||
call##_cleanup, \
|
||||
#call, \
|
||||
}; \
|
||||
any_badbuf(&info); \
|
||||
}
|
||||
|
||||
T(read);
|
||||
|
||||
@@ -44,182 +44,119 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
|
||||
enum rwtestmodes {
|
||||
RW_TEST_NONE,
|
||||
RW_TEST_RDONLY,
|
||||
RW_TEST_WRONLY,
|
||||
RW_TEST_NONE,
|
||||
RW_TEST_RDONLY,
|
||||
RW_TEST_WRONLY,
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
read_badfd(int fd)
|
||||
{
|
||||
char buf[128];
|
||||
return read(fd, buf, sizeof(buf));
|
||||
static int read_badfd(int fd) {
|
||||
char buf[128];
|
||||
return read(fd, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
write_badfd(int fd)
|
||||
{
|
||||
char buf[128];
|
||||
memset(buf, 'a', sizeof(buf));
|
||||
return write(fd, buf, sizeof(buf));
|
||||
static int write_badfd(int fd) {
|
||||
char buf[128];
|
||||
memset(buf, 'a', sizeof(buf));
|
||||
return write(fd, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int close_badfd(int fd) { return close(fd); }
|
||||
|
||||
static
|
||||
int
|
||||
close_badfd(int fd)
|
||||
{
|
||||
return close(fd);
|
||||
static int ioctl_badfd(int fd) { return ioctl(fd, 0, NULL); }
|
||||
|
||||
static int lseek_badfd(int fd) { return lseek(fd, 0, SEEK_SET); }
|
||||
|
||||
static int fsync_badfd(int fd) { return fsync(fd); }
|
||||
|
||||
static int ftruncate_badfd(int fd) { return ftruncate(fd, 60); }
|
||||
|
||||
static int fstat_badfd(int fd) {
|
||||
struct stat sb;
|
||||
return fstat(fd, &sb);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
ioctl_badfd(int fd)
|
||||
{
|
||||
return ioctl(fd, 0, NULL);
|
||||
static int getdirentry_badfd(int fd) {
|
||||
char buf[32];
|
||||
return getdirentry(fd, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
lseek_badfd(int fd)
|
||||
{
|
||||
return lseek(fd, 0, SEEK_SET);
|
||||
static int dup2_badfd(int fd) {
|
||||
/* use the +1 to avoid doing dup2(CLOSED_FD, CLOSED_FD) */
|
||||
return dup2(fd, CLOSED_FD + 1);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
fsync_badfd(int fd)
|
||||
{
|
||||
return fsync(fd);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
ftruncate_badfd(int fd)
|
||||
{
|
||||
return ftruncate(fd, 60);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
fstat_badfd(int fd)
|
||||
{
|
||||
struct stat sb;
|
||||
return fstat(fd, &sb);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
getdirentry_badfd(int fd)
|
||||
{
|
||||
char buf[32];
|
||||
return getdirentry(fd, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
dup2_badfd(int fd)
|
||||
{
|
||||
/* use the +1 to avoid doing dup2(CLOSED_FD, CLOSED_FD) */
|
||||
return dup2(fd, CLOSED_FD+1);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dup2_cleanup(void)
|
||||
{
|
||||
close(CLOSED_FD+1);
|
||||
}
|
||||
static void dup2_cleanup(void) { close(CLOSED_FD + 1); }
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
any_badfd(int (*func)(int fd), void (*cleanup)(void), const char *callname,
|
||||
int fd, const char *fddesc)
|
||||
{
|
||||
int rv;
|
||||
static void any_badfd(int (*func)(int fd), void (*cleanup)(void),
|
||||
const char *callname, int fd, const char *fddesc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s using %s", callname, fddesc);
|
||||
rv = func(fd);
|
||||
report_check(rv, errno, EBADF);
|
||||
if (cleanup) {
|
||||
cleanup();
|
||||
}
|
||||
report_begin("%s using %s", callname, fddesc);
|
||||
rv = func(fd);
|
||||
report_check(rv, errno, EBADF);
|
||||
if (cleanup) {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
runtest(int (*func)(int fd), void (*cleanup)(void), const char *callname,
|
||||
enum rwtestmodes rw)
|
||||
{
|
||||
int fd;
|
||||
static void runtest(int (*func)(int fd), void (*cleanup)(void),
|
||||
const char *callname, enum rwtestmodes rw) {
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* If adding cases, also see bad_dup2.c
|
||||
*/
|
||||
/*
|
||||
* If adding cases, also see bad_dup2.c
|
||||
*/
|
||||
|
||||
/* basic invalid case: fd -1 */
|
||||
any_badfd(func, cleanup, callname, -1, "fd -1");
|
||||
/* basic invalid case: fd -1 */
|
||||
any_badfd(func, cleanup, callname, -1, "fd -1");
|
||||
|
||||
/* also try -5 in case -1 is special somehow */
|
||||
any_badfd(func, cleanup, callname, -5, "fd -5");
|
||||
/* also try -5 in case -1 is special somehow */
|
||||
any_badfd(func, cleanup, callname, -5, "fd -5");
|
||||
|
||||
/* try a fd we know is closed */
|
||||
any_badfd(func, cleanup, callname, CLOSED_FD, "closed fd");
|
||||
/* try a fd we know is closed */
|
||||
any_badfd(func, cleanup, callname, CLOSED_FD, "closed fd");
|
||||
|
||||
/* try a positive fd we know is out of range */
|
||||
any_badfd(func, cleanup, callname, IMPOSSIBLE_FD, "impossible fd");
|
||||
/* try a positive fd we know is out of range */
|
||||
any_badfd(func, cleanup, callname, IMPOSSIBLE_FD, "impossible fd");
|
||||
|
||||
/* test for off-by-one errors */
|
||||
/* test for off-by-one errors */
|
||||
#ifdef OPEN_MAX
|
||||
any_badfd(func, cleanup, callname, OPEN_MAX, "fd OPEN_MAX");
|
||||
any_badfd(func, cleanup, callname, OPEN_MAX, "fd OPEN_MAX");
|
||||
#else
|
||||
warnx("Warning: OPEN_MAX not defined, test skipped");
|
||||
warnx("Warning: OPEN_MAX not defined, test skipped");
|
||||
#endif
|
||||
|
||||
if (rw == RW_TEST_RDONLY) {
|
||||
fd = reopen_testfile(O_RDONLY|O_CREAT);
|
||||
if (fd < 0) {
|
||||
/* already printed a message */
|
||||
}
|
||||
else {
|
||||
any_badfd(func, cleanup, callname, fd,
|
||||
"fd opened read-only");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
if (rw == RW_TEST_WRONLY) {
|
||||
fd = reopen_testfile(O_WRONLY|O_CREAT);
|
||||
if (fd < 0) {
|
||||
/* already printed a message */
|
||||
}
|
||||
else {
|
||||
any_badfd(func, cleanup, callname, fd,
|
||||
"fd opened write-only");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
if (rw == RW_TEST_RDONLY) {
|
||||
fd = reopen_testfile(O_RDONLY | O_CREAT);
|
||||
if (fd < 0) {
|
||||
/* already printed a message */
|
||||
} else {
|
||||
any_badfd(func, cleanup, callname, fd, "fd opened read-only");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
if (rw == RW_TEST_WRONLY) {
|
||||
fd = reopen_testfile(O_WRONLY | O_CREAT);
|
||||
if (fd < 0) {
|
||||
/* already printed a message */
|
||||
} else {
|
||||
any_badfd(func, cleanup, callname, fd, "fd opened write-only");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#define T(call, rw) \
|
||||
void \
|
||||
test_##call##_fd(void) \
|
||||
{ \
|
||||
runtest(call##_badfd, NULL, #call, rw); \
|
||||
}
|
||||
#define T(call, rw) \
|
||||
void test_##call##_fd(void) { runtest(call##_badfd, NULL, #call, rw); }
|
||||
|
||||
#define TC(call, rw) \
|
||||
void \
|
||||
test_##call##_fd(void) \
|
||||
{ \
|
||||
runtest(call##_badfd, call##_cleanup, #call, rw);\
|
||||
#define TC(call, rw) \
|
||||
void test_##call##_fd(void) { \
|
||||
runtest(call##_badfd, call##_cleanup, #call, rw); \
|
||||
}
|
||||
|
||||
T(read, RW_TEST_WRONLY);
|
||||
|
||||
@@ -44,151 +44,83 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
int
|
||||
open_badpath(const char *path)
|
||||
{
|
||||
return open(path, O_RDONLY);
|
||||
static int open_badpath(const char *path) { return open(path, O_RDONLY); }
|
||||
|
||||
static int remove_badpath(const char *path) { return remove(path); }
|
||||
|
||||
static int rename_badpath1(const char *path) { return rename(path, TESTFILE); }
|
||||
|
||||
static int rename_badpath2(const char *path) { return rename(TESTFILE, path); }
|
||||
|
||||
static int link_badpath1(const char *path) { return link(path, TESTFILE); }
|
||||
|
||||
static int link_badpath2(const char *path) { return link(TESTFILE, path); }
|
||||
|
||||
static int mkdir_badpath(const char *path) { return mkdir(path, 0775); }
|
||||
|
||||
static int rmdir_badpath(const char *path) { return rmdir(path); }
|
||||
|
||||
static int chdir_badpath(const char *path) { return chdir(path); }
|
||||
|
||||
static int symlink_badpath1(const char *path) {
|
||||
return symlink(path, TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
remove_badpath(const char *path)
|
||||
{
|
||||
return remove(path);
|
||||
static int symlink_badpath2(const char *path) {
|
||||
return symlink(TESTFILE, path);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
rename_badpath1(const char *path)
|
||||
{
|
||||
return rename(path, TESTFILE);
|
||||
static int readlink_badpath(const char *path) {
|
||||
char buf[128];
|
||||
return readlink(path, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
rename_badpath2(const char *path)
|
||||
{
|
||||
return rename(TESTFILE, path);
|
||||
static int lstat_badpath(const char *name) {
|
||||
struct stat sb;
|
||||
return lstat(name, &sb);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
link_badpath1(const char *path)
|
||||
{
|
||||
return link(path, TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
link_badpath2(const char *path)
|
||||
{
|
||||
return link(TESTFILE, path);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
mkdir_badpath(const char *path)
|
||||
{
|
||||
return mkdir(path, 0775);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
rmdir_badpath(const char *path)
|
||||
{
|
||||
return rmdir(path);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
chdir_badpath(const char *path)
|
||||
{
|
||||
return chdir(path);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
symlink_badpath1(const char *path)
|
||||
{
|
||||
return symlink(path, TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
symlink_badpath2(const char *path)
|
||||
{
|
||||
return symlink(TESTFILE, path);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
readlink_badpath(const char *path)
|
||||
{
|
||||
char buf[128];
|
||||
return readlink(path, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
lstat_badpath(const char *name)
|
||||
{
|
||||
struct stat sb;
|
||||
return lstat(name, &sb);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
stat_badpath(const char *name)
|
||||
{
|
||||
struct stat sb;
|
||||
return stat(name, &sb);
|
||||
static int stat_badpath(const char *name) {
|
||||
struct stat sb;
|
||||
return stat(name, &sb);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
common_badpath(int (*func)(const char *path), int mk, int rm, const char *path,
|
||||
const char *call, const char *pathdesc)
|
||||
{
|
||||
int rv;
|
||||
static void common_badpath(int (*func)(const char *path), int mk, int rm,
|
||||
const char *path, const char *call,
|
||||
const char *pathdesc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s with %s path", call, pathdesc);
|
||||
report_begin("%s with %s path", call, pathdesc);
|
||||
|
||||
if (mk) {
|
||||
if (create_testfile()<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mk) {
|
||||
if (create_testfile() < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rv = func(path);
|
||||
report_check(rv, errno, EFAULT);
|
||||
rv = func(path);
|
||||
report_check(rv, errno, EFAULT);
|
||||
|
||||
if (mk || rm) {
|
||||
remove(TESTFILE);
|
||||
}
|
||||
if (mk || rm) {
|
||||
remove(TESTFILE);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
any_badpath(int (*func)(const char *path), const char *call, int mk, int rm)
|
||||
{
|
||||
common_badpath(func, mk, rm, NULL, call, "NULL");
|
||||
common_badpath(func, mk, rm, INVAL_PTR, call, "invalid-pointer");
|
||||
common_badpath(func, mk, rm, KERN_PTR, call, "kernel-pointer");
|
||||
static void any_badpath(int (*func)(const char *path), const char *call, int mk,
|
||||
int rm) {
|
||||
common_badpath(func, mk, rm, NULL, call, "NULL");
|
||||
common_badpath(func, mk, rm, INVAL_PTR, call, "invalid-pointer");
|
||||
common_badpath(func, mk, rm, KERN_PTR, call, "kernel-pointer");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/* functions with one pathname */
|
||||
#define T(call) \
|
||||
void \
|
||||
test_##call##_path(void) \
|
||||
{ \
|
||||
any_badpath(call##_badpath, #call, 0, 0); \
|
||||
}
|
||||
#define T(call) \
|
||||
void test_##call##_path(void) { any_badpath(call##_badpath, #call, 0, 0); }
|
||||
|
||||
T(open);
|
||||
T(remove);
|
||||
@@ -200,12 +132,10 @@ T(stat);
|
||||
T(lstat);
|
||||
|
||||
/* functions with two pathnames */
|
||||
#define T2(call) \
|
||||
void \
|
||||
test_##call##_paths(void) \
|
||||
{ \
|
||||
any_badpath(call##_badpath1, #call "(arg1)", 0, 1); \
|
||||
any_badpath(call##_badpath2, #call "(arg2)", 1, 1); \
|
||||
#define T2(call) \
|
||||
void test_##call##_paths(void) { \
|
||||
any_badpath(call##_badpath1, #call "(arg1)", 0, 1); \
|
||||
any_badpath(call##_badpath2, #call "(arg2)", 1, 1); \
|
||||
}
|
||||
|
||||
T2(rename);
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
*/
|
||||
|
||||
#if defined(__mips__)
|
||||
#define KERN_PTR ((void *)0x80000000) /* addr within kernel */
|
||||
#define INVAL_PTR ((void *)0x40000000) /* addr not part of program */
|
||||
#define KERN_PTR ((void *)0x80000000) /* addr within kernel */
|
||||
#define INVAL_PTR ((void *)0x40000000) /* addr not part of program */
|
||||
#else
|
||||
#error "Please fix this"
|
||||
#endif
|
||||
@@ -45,16 +45,16 @@
|
||||
* We assume CLOSED_FD is a legal fd that won't be open when we're running.
|
||||
* CLOSED_FD+1 should also be legal and not open.
|
||||
*/
|
||||
#define CLOSED_FD 10
|
||||
#define CLOSED_FD 10
|
||||
|
||||
/* We assume IMPOSSIBLE_FD is a fd that is completely not allowed. */
|
||||
#define IMPOSSIBLE_FD 1234567890
|
||||
#define IMPOSSIBLE_FD 1234567890
|
||||
|
||||
/* We assume this pid won't exist while we're running. Change as needed. */
|
||||
#define NONEXIST_PID 34000
|
||||
#define NONEXIST_PID 34000
|
||||
|
||||
/* An arbitrary process exit code that hopefully won't occur by accident */
|
||||
#define MAGIC_STATUS 107
|
||||
#define MAGIC_STATUS 107
|
||||
|
||||
/* An ioctl that doesn't exist */
|
||||
#define NONEXIST_IOCTL 12345
|
||||
#define NONEXIST_IOCTL 12345
|
||||
|
||||
@@ -42,74 +42,68 @@
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int
|
||||
open_testfile(const char *string)
|
||||
{
|
||||
int fd, rv;
|
||||
size_t len;
|
||||
int open_testfile(const char *string) {
|
||||
int fd, rv;
|
||||
size_t len;
|
||||
|
||||
fd = open(TESTFILE, O_RDWR|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd<0) {
|
||||
report_warn("creating %s: failed", TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
fd = open(TESTFILE, O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
report_warn("creating %s: failed", TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (string) {
|
||||
len = strlen(string);
|
||||
rv = write(fd, string, len);
|
||||
if (rv<0) {
|
||||
report_warn("write to %s failed", TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
if ((unsigned)rv != len) {
|
||||
report_warn("write to %s got short count", TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
rv = lseek(fd, 0, SEEK_SET);
|
||||
if (rv<0) {
|
||||
report_warn("rewind of %s failed", TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
if (string) {
|
||||
len = strlen(string);
|
||||
rv = write(fd, string, len);
|
||||
if (rv < 0) {
|
||||
report_warn("write to %s failed", TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
if ((unsigned)rv != len) {
|
||||
report_warn("write to %s got short count", TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
rv = lseek(fd, 0, SEEK_SET);
|
||||
if (rv < 0) {
|
||||
report_warn("rewind of %s failed", TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
create_testfile(void)
|
||||
{
|
||||
int fd, rv;
|
||||
int create_testfile(void) {
|
||||
int fd, rv;
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
return -1;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = close(fd);
|
||||
if (rv<0) {
|
||||
report_warn("closing %s failed", TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
rv = close(fd);
|
||||
if (rv < 0) {
|
||||
report_warn("closing %s failed", TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
reopen_testfile(int openflags)
|
||||
{
|
||||
int fd;
|
||||
int reopen_testfile(int openflags) {
|
||||
int fd;
|
||||
|
||||
fd = open(TESTFILE, openflags, 0664);
|
||||
if (fd < 0) {
|
||||
report_warn("reopening %s: failed", TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
fd = open(TESTFILE, openflags, 0664);
|
||||
if (fd < 0) {
|
||||
report_warn("reopening %s: failed", TESTFILE);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -117,173 +111,155 @@ reopen_testfile(int openflags)
|
||||
* otherwise it has to communicate to the caller which to call and
|
||||
* that's a pain.
|
||||
*/
|
||||
int
|
||||
create_testdir(void)
|
||||
{
|
||||
int rv;
|
||||
rv = mkdir(TESTDIR, 0775);
|
||||
if (rv<0) {
|
||||
if (errno == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
report_warnx("mkdir unimplemented; cannot run test");
|
||||
report_skipped();
|
||||
}
|
||||
else {
|
||||
report_warn("mkdir %s failed", TESTDIR);
|
||||
report_aborted();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
int create_testdir(void) {
|
||||
int rv;
|
||||
rv = mkdir(TESTDIR, 0775);
|
||||
if (rv < 0) {
|
||||
if (errno == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
report_warnx("mkdir unimplemented; cannot run test");
|
||||
report_skipped();
|
||||
} else {
|
||||
report_warn("mkdir %s failed", TESTDIR);
|
||||
report_aborted();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
create_testlink(void)
|
||||
{
|
||||
int rv;
|
||||
rv = symlink("blahblah", TESTLINK);
|
||||
if (rv<0) {
|
||||
report_warn("making symlink %s failed", TESTLINK);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
int create_testlink(void) {
|
||||
int rv;
|
||||
rv = symlink("blahblah", TESTLINK);
|
||||
if (rv < 0) {
|
||||
report_warn("making symlink %s failed", TESTLINK);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
struct {
|
||||
int ch;
|
||||
int asst;
|
||||
const char *name;
|
||||
void (*f)(void);
|
||||
} ops[] = {
|
||||
{ 'a', 2, "execv", test_execv },
|
||||
{ 'b', 2, "waitpid", test_waitpid },
|
||||
{ 'c', 2, "open", test_open },
|
||||
{ 'd', 2, "read", test_read },
|
||||
{ 'e', 2, "write", test_write },
|
||||
{ 'f', 2, "close", test_close },
|
||||
{ 'g', 0, "reboot", test_reboot },
|
||||
{ 'h', 3, "sbrk", test_sbrk },
|
||||
{ 'i', 5, "ioctl", test_ioctl },
|
||||
{ 'j', 2, "lseek", test_lseek },
|
||||
{ 'k', 4, "fsync", test_fsync },
|
||||
{ 'l', 4, "ftruncate", test_ftruncate },
|
||||
{ 'm', 4, "fstat", test_fstat },
|
||||
{ 'n', 4, "remove", test_remove },
|
||||
{ 'o', 4, "rename", test_rename },
|
||||
{ 'p', 5, "link", test_link },
|
||||
{ 'q', 4, "mkdir", test_mkdir },
|
||||
{ 'r', 4, "rmdir", test_rmdir },
|
||||
{ 's', 2, "chdir", test_chdir },
|
||||
{ 't', 4, "getdirentry", test_getdirentry },
|
||||
{ 'u', 5, "symlink", test_symlink },
|
||||
{ 'v', 5, "readlink", test_readlink },
|
||||
{ 'w', 2, "dup2", test_dup2 },
|
||||
{ 'x', 5, "pipe", test_pipe },
|
||||
{ 'y', 5, "__time", test_time },
|
||||
{ 'z', 2, "__getcwd", test_getcwd },
|
||||
{ '{', 5, "stat", test_stat },
|
||||
{ '|', 5, "lstat", test_lstat },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
static struct {
|
||||
int ch;
|
||||
int asst;
|
||||
const char *name;
|
||||
void (*f)(void);
|
||||
} ops[] = {{'a', 2, "execv", test_execv},
|
||||
{'b', 2, "waitpid", test_waitpid},
|
||||
{'c', 2, "open", test_open},
|
||||
{'d', 2, "read", test_read},
|
||||
{'e', 2, "write", test_write},
|
||||
{'f', 2, "close", test_close},
|
||||
{'g', 0, "reboot", test_reboot},
|
||||
{'h', 3, "sbrk", test_sbrk},
|
||||
{'i', 5, "ioctl", test_ioctl},
|
||||
{'j', 2, "lseek", test_lseek},
|
||||
{'k', 4, "fsync", test_fsync},
|
||||
{'l', 4, "ftruncate", test_ftruncate},
|
||||
{'m', 4, "fstat", test_fstat},
|
||||
{'n', 4, "remove", test_remove},
|
||||
{'o', 4, "rename", test_rename},
|
||||
{'p', 5, "link", test_link},
|
||||
{'q', 4, "mkdir", test_mkdir},
|
||||
{'r', 4, "rmdir", test_rmdir},
|
||||
{'s', 2, "chdir", test_chdir},
|
||||
{'t', 4, "getdirentry", test_getdirentry},
|
||||
{'u', 5, "symlink", test_symlink},
|
||||
{'v', 5, "readlink", test_readlink},
|
||||
{'w', 2, "dup2", test_dup2},
|
||||
{'x', 5, "pipe", test_pipe},
|
||||
{'y', 5, "__time", test_time},
|
||||
{'z', 2, "__getcwd", test_getcwd},
|
||||
{'{', 5, "stat", test_stat},
|
||||
{'|', 5, "lstat", test_lstat},
|
||||
{0, 0, NULL, NULL}};
|
||||
|
||||
#define LOWEST 'a'
|
||||
#define LOWEST 'a'
|
||||
#define HIGHEST '|'
|
||||
|
||||
static
|
||||
void
|
||||
menu(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; ops[i].name; i++) {
|
||||
printf("[%c] %-24s", ops[i].ch, ops[i].name);
|
||||
if (i%2==1) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (i%2==1) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("[1] %-24s", "asst1");
|
||||
printf("[2] %-24s\n", "asst2");
|
||||
printf("[3] %-24s", "asst3");
|
||||
printf("[4] %-24s\n", "asst4");
|
||||
printf("[*] %-24s", "all");
|
||||
printf("[!] %-24s\n", "quit");
|
||||
static void menu(void) {
|
||||
int i;
|
||||
for (i = 0; ops[i].name; i++) {
|
||||
printf("[%c] %-24s", ops[i].ch, ops[i].name);
|
||||
if (i % 2 == 1) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (i % 2 == 1) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("[1] %-24s", "asst1");
|
||||
printf("[2] %-24s\n", "asst2");
|
||||
printf("[3] %-24s", "asst3");
|
||||
printf("[4] %-24s\n", "asst4");
|
||||
printf("[*] %-24s", "all");
|
||||
printf("[!] %-24s\n", "quit");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
runit(int op)
|
||||
{
|
||||
int i, k;
|
||||
static void runit(int op) {
|
||||
int i, k;
|
||||
|
||||
if (op=='!') {
|
||||
exit(0);
|
||||
}
|
||||
if (op == '!') {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (op=='?') {
|
||||
menu();
|
||||
return;
|
||||
}
|
||||
if (op == '?') {
|
||||
menu();
|
||||
return;
|
||||
}
|
||||
|
||||
if (op=='*') {
|
||||
for (i=0; ops[i].name; i++) {
|
||||
printf("[%s]\n", ops[i].name);
|
||||
ops[i].f();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (op == '*') {
|
||||
for (i = 0; ops[i].name; i++) {
|
||||
printf("[%s]\n", ops[i].name);
|
||||
ops[i].f();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (op>='1' && op <= '4') {
|
||||
k = op-'0';
|
||||
for (i=0; ops[i].name; i++) {
|
||||
if (ops[i].asst <= k) {
|
||||
printf("[%s]\n", ops[i].name);
|
||||
ops[i].f();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (op >= '1' && op <= '4') {
|
||||
k = op - '0';
|
||||
for (i = 0; ops[i].name; i++) {
|
||||
if (ops[i].asst <= k) {
|
||||
printf("[%s]\n", ops[i].name);
|
||||
ops[i].f();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (op < LOWEST || op > HIGHEST) {
|
||||
printf("Invalid request %c\n", op);
|
||||
return;
|
||||
}
|
||||
if (op < LOWEST || op > HIGHEST) {
|
||||
printf("Invalid request %c\n", op);
|
||||
return;
|
||||
}
|
||||
|
||||
ops[op-'a'].f();
|
||||
ops[op - 'a'].f();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int op, i, j;
|
||||
int main(int argc, char **argv) {
|
||||
int op, i, j;
|
||||
|
||||
printf("[%c-%c, 1-4, *, ?=menu, !=quit]\n", LOWEST, HIGHEST);
|
||||
printf("[%c-%c, 1-4, *, ?=menu, !=quit]\n", LOWEST, HIGHEST);
|
||||
|
||||
if (argc > 1) {
|
||||
for (i=1; i<argc; i++) {
|
||||
for (j=0; argv[i][j]; j++) {
|
||||
printf("Choose: %c\n",
|
||||
argv[i][j]);
|
||||
runit(argv[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
menu();
|
||||
while (1) {
|
||||
printf("Choose: ");
|
||||
op = getchar();
|
||||
if (op==EOF) {
|
||||
break;
|
||||
}
|
||||
printf("%c\n", op);
|
||||
runit(op);
|
||||
}
|
||||
}
|
||||
if (argc > 1) {
|
||||
for (i = 1; i < argc; i++) {
|
||||
for (j = 0; argv[i][j]; j++) {
|
||||
printf("Choose: %c\n", argv[i][j]);
|
||||
runit(argv[i][j]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
menu();
|
||||
while (1) {
|
||||
printf("Choose: ");
|
||||
op = getchar();
|
||||
if (op == EOF) {
|
||||
break;
|
||||
}
|
||||
printf("%c\n", op);
|
||||
runit(op);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -58,63 +58,50 @@ static size_t outbufpos;
|
||||
/*
|
||||
* Print things.
|
||||
*/
|
||||
static
|
||||
void
|
||||
vsay(const char *fmt, va_list ap)
|
||||
{
|
||||
size_t begin, i;
|
||||
static void vsay(const char *fmt, va_list ap) {
|
||||
size_t begin, i;
|
||||
|
||||
assert(outbufpos < sizeof(outbuf));
|
||||
assert(outbufpos < sizeof(outbuf));
|
||||
|
||||
begin = outbufpos;
|
||||
vsnprintf(outbuf + outbufpos, sizeof(outbuf) - outbufpos, fmt, ap);
|
||||
outbufpos = strlen(outbuf);
|
||||
begin = outbufpos;
|
||||
vsnprintf(outbuf + outbufpos, sizeof(outbuf) - outbufpos, fmt, ap);
|
||||
outbufpos = strlen(outbuf);
|
||||
|
||||
for (i=begin; i<outbufpos; i++) {
|
||||
if (outbuf[i] == '\n') {
|
||||
horizpos = 0;
|
||||
}
|
||||
else {
|
||||
horizpos++;
|
||||
}
|
||||
}
|
||||
for (i = begin; i < outbufpos; i++) {
|
||||
if (outbuf[i] == '\n') {
|
||||
horizpos = 0;
|
||||
} else {
|
||||
horizpos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
say(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static void say(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsay(fmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
vsay(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Indent to a given horizontal position.
|
||||
*/
|
||||
static
|
||||
void
|
||||
indent_to(size_t pos)
|
||||
{
|
||||
while (horizpos < pos) {
|
||||
assert(outbufpos < sizeof(outbuf) - 1);
|
||||
outbuf[outbufpos++] = ' ';
|
||||
outbuf[outbufpos] = 0;
|
||||
horizpos++;
|
||||
}
|
||||
static void indent_to(size_t pos) {
|
||||
while (horizpos < pos) {
|
||||
assert(outbufpos < sizeof(outbuf) - 1);
|
||||
outbuf[outbufpos++] = ' ';
|
||||
outbuf[outbufpos] = 0;
|
||||
horizpos++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush the output.
|
||||
*/
|
||||
static
|
||||
void
|
||||
flush(void)
|
||||
{
|
||||
write(STDOUT_FILENO, outbuf, outbufpos);
|
||||
outbufpos = 0;
|
||||
static void flush(void) {
|
||||
write(STDOUT_FILENO, outbuf, outbufpos);
|
||||
outbufpos = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -123,28 +110,24 @@ flush(void)
|
||||
* Begin a test. This flushes the description so it can be seen before
|
||||
* the test happens, in case the test explodes or deadlocks the system.
|
||||
*/
|
||||
void
|
||||
report_begin(const char *descfmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void report_begin(const char *descfmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
say("badcall: ");
|
||||
va_start(ap, descfmt);
|
||||
vsay(descfmt, ap);
|
||||
va_end(ap);
|
||||
say("... ");
|
||||
flush();
|
||||
say("badcall: ");
|
||||
va_start(ap, descfmt);
|
||||
vsay(descfmt, ap);
|
||||
va_end(ap);
|
||||
say("... ");
|
||||
flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare to be able to print subreports.
|
||||
*/
|
||||
void
|
||||
report_hassubs(void)
|
||||
{
|
||||
subpos = horizpos;
|
||||
say("\n");
|
||||
flush();
|
||||
void report_hassubs(void) {
|
||||
subpos = horizpos;
|
||||
say("\n");
|
||||
flush();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -152,17 +135,15 @@ report_hassubs(void)
|
||||
* subreports are in subprocesses and we want each one to print a
|
||||
* whole line at once to avoid output interleaving.
|
||||
*/
|
||||
void
|
||||
report_beginsub(const char *descfmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void report_beginsub(const char *descfmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
assert(horizpos == 0);
|
||||
say(" ");
|
||||
va_start(ap, descfmt);
|
||||
vsay(descfmt, ap);
|
||||
va_end(ap);
|
||||
indent_to(subpos);
|
||||
assert(horizpos == 0);
|
||||
say(" ");
|
||||
va_start(ap, descfmt);
|
||||
vsay(descfmt, ap);
|
||||
va_end(ap);
|
||||
indent_to(subpos);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,52 +151,45 @@ report_beginsub(const char *descfmt, ...)
|
||||
* extra line for the warning. The warnx form is the same but doesn't
|
||||
* add errno.
|
||||
*/
|
||||
void
|
||||
report_warn(const char *fmt, ...)
|
||||
{
|
||||
size_t pos;
|
||||
const char *errmsg;
|
||||
va_list ap;
|
||||
void report_warn(const char *fmt, ...) {
|
||||
size_t pos;
|
||||
const char *errmsg;
|
||||
va_list ap;
|
||||
|
||||
pos = horizpos;
|
||||
errmsg = strerror(errno);
|
||||
say("\n OOPS: ");
|
||||
va_start(ap, fmt);
|
||||
vsay(fmt, ap);
|
||||
va_end(ap);
|
||||
say(": %s\n", errmsg);
|
||||
indent_to(pos);
|
||||
flush();
|
||||
pos = horizpos;
|
||||
errmsg = strerror(errno);
|
||||
say("\n OOPS: ");
|
||||
va_start(ap, fmt);
|
||||
vsay(fmt, ap);
|
||||
va_end(ap);
|
||||
say(": %s\n", errmsg);
|
||||
indent_to(pos);
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
report_warnx(const char *fmt, ...)
|
||||
{
|
||||
size_t pos;
|
||||
va_list ap;
|
||||
void report_warnx(const char *fmt, ...) {
|
||||
size_t pos;
|
||||
va_list ap;
|
||||
|
||||
pos = horizpos;
|
||||
say("\n oops: ");
|
||||
va_start(ap, fmt);
|
||||
vsay(fmt, ap);
|
||||
va_end(ap);
|
||||
say("\n");
|
||||
indent_to(pos);
|
||||
flush();
|
||||
pos = horizpos;
|
||||
say("\n oops: ");
|
||||
va_start(ap, fmt);
|
||||
vsay(fmt, ap);
|
||||
va_end(ap);
|
||||
say("\n");
|
||||
indent_to(pos);
|
||||
flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a system call result.
|
||||
*/
|
||||
void
|
||||
report_result(int rv, int error)
|
||||
{
|
||||
if (rv == -1) {
|
||||
say("%s ", strerror(error));
|
||||
}
|
||||
else {
|
||||
say("Success ");
|
||||
}
|
||||
void report_result(int rv, int error) {
|
||||
if (rv == -1) {
|
||||
say("%s ", strerror(error));
|
||||
} else {
|
||||
say("Success ");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -227,13 +201,11 @@ report_result(int rv, int error)
|
||||
*
|
||||
* XXX this is pretty gross.
|
||||
*/
|
||||
void
|
||||
report_saw_enosys(void)
|
||||
{
|
||||
size_t pos = horizpos;
|
||||
void report_saw_enosys(void) {
|
||||
size_t pos = horizpos;
|
||||
|
||||
horizpos = 0;
|
||||
indent_to(pos);
|
||||
horizpos = 0;
|
||||
indent_to(pos);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -241,38 +213,19 @@ report_saw_enosys(void)
|
||||
* in the result column, and add the final newline.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
report_end(const char *msg)
|
||||
{
|
||||
indent_to(RESULT_COLUMN);
|
||||
say("%s\n", msg);
|
||||
flush();
|
||||
static void report_end(const char *msg) {
|
||||
indent_to(RESULT_COLUMN);
|
||||
say("%s\n", msg);
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
report_passed(void)
|
||||
{
|
||||
report_end("passed");
|
||||
}
|
||||
void report_passed(void) { report_end("passed"); }
|
||||
|
||||
void
|
||||
report_failure(void)
|
||||
{
|
||||
report_end("FAILURE");
|
||||
}
|
||||
void report_failure(void) { report_end("FAILURE"); }
|
||||
|
||||
void
|
||||
report_skipped(void)
|
||||
{
|
||||
report_end("------");
|
||||
}
|
||||
void report_skipped(void) { report_end("------"); }
|
||||
|
||||
void
|
||||
report_aborted(void)
|
||||
{
|
||||
report_end("ABORTED");
|
||||
}
|
||||
void report_aborted(void) { report_end("ABORTED"); }
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -282,69 +235,56 @@ report_aborted(void)
|
||||
* matches one or more expected results.
|
||||
*/
|
||||
|
||||
void
|
||||
report_survival(int rv, int error)
|
||||
{
|
||||
/* allow any error as long as we survive */
|
||||
report_result(rv, error);
|
||||
report_passed();
|
||||
void report_survival(int rv, int error) {
|
||||
/* allow any error as long as we survive */
|
||||
report_result(rv, error);
|
||||
report_passed();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
report_checkN(int rv, int error, int *right_errors, int right_num)
|
||||
{
|
||||
int i, goterror;
|
||||
static void report_checkN(int rv, int error, int *right_errors, int right_num) {
|
||||
int i, goterror;
|
||||
|
||||
if (rv==-1) {
|
||||
goterror = error;
|
||||
}
|
||||
else {
|
||||
goterror = 0;
|
||||
}
|
||||
if (rv == -1) {
|
||||
goterror = error;
|
||||
} else {
|
||||
goterror = 0;
|
||||
}
|
||||
|
||||
for (i=0; i<right_num; i++) {
|
||||
if (goterror == right_errors[i]) {
|
||||
report_result(rv, error);
|
||||
report_passed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < right_num; i++) {
|
||||
if (goterror == right_errors[i]) {
|
||||
report_result(rv, error);
|
||||
report_passed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (goterror == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
say("(unimplemented) ");
|
||||
report_skipped();
|
||||
}
|
||||
else {
|
||||
report_result(rv, error);
|
||||
report_failure();
|
||||
}
|
||||
if (goterror == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
say("(unimplemented) ");
|
||||
report_skipped();
|
||||
} else {
|
||||
report_result(rv, error);
|
||||
report_failure();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
report_check(int rv, int error, int right_error)
|
||||
{
|
||||
report_checkN(rv, error, &right_error, 1);
|
||||
void report_check(int rv, int error, int right_error) {
|
||||
report_checkN(rv, error, &right_error, 1);
|
||||
}
|
||||
|
||||
void
|
||||
report_check2(int rv, int error, int okerr1, int okerr2)
|
||||
{
|
||||
int ok[2];
|
||||
void report_check2(int rv, int error, int okerr1, int okerr2) {
|
||||
int ok[2];
|
||||
|
||||
ok[0] = okerr1;
|
||||
ok[1] = okerr2;
|
||||
report_checkN(rv, error, ok, 2);
|
||||
ok[0] = okerr1;
|
||||
ok[1] = okerr2;
|
||||
report_checkN(rv, error, ok, 2);
|
||||
}
|
||||
|
||||
void
|
||||
report_check3(int rv, int error, int okerr1, int okerr2, int okerr3)
|
||||
{
|
||||
int ok[3];
|
||||
void report_check3(int rv, int error, int okerr1, int okerr2, int okerr3) {
|
||||
int ok[3];
|
||||
|
||||
ok[0] = okerr1;
|
||||
ok[1] = okerr2;
|
||||
ok[2] = okerr3;
|
||||
report_checkN(rv, error, ok, 3);
|
||||
ok[0] = okerr1;
|
||||
ok[1] = okerr2;
|
||||
ok[2] = okerr3;
|
||||
report_checkN(rv, error, ok, 3);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*/
|
||||
|
||||
#define TESTFILE "badcallfile"
|
||||
#define TESTDIR "badcalldir"
|
||||
#define TESTDIR "badcalldir"
|
||||
#define TESTLINK "badcalllink"
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
@@ -106,7 +106,7 @@ void test_ioctl(void);
|
||||
void test_lseek(void);
|
||||
void test_fsync(void);
|
||||
void test_ftruncate(void);
|
||||
void test_fstat(void); /* in bad_stat.c */
|
||||
void test_fstat(void); /* in bad_stat.c */
|
||||
void test_remove(void);
|
||||
void test_rename(void);
|
||||
void test_link(void);
|
||||
@@ -121,4 +121,4 @@ void test_pipe(void);
|
||||
void test_time(void);
|
||||
void test_getcwd(void);
|
||||
void test_stat(void);
|
||||
void test_lstat(void); /* in bad_stat.c */
|
||||
void test_lstat(void); /* in bad_stat.c */
|
||||
|
||||
@@ -52,336 +52,288 @@ static char word4050[4051];
|
||||
static char word16320[16321];
|
||||
static char word65500[65501];
|
||||
|
||||
static
|
||||
void
|
||||
fill(char *buf, size_t buflen)
|
||||
{
|
||||
static const char *const names[22] = {
|
||||
"Alhammitt", "Biffa", "Cennoreth", "Dastgandlen", "Enblith",
|
||||
"Fenna", "Gull", "Hern", "Hildrida", "Kankredin", "Kialan",
|
||||
"Lenina", "Manaliabrid", "Mayelbridwen", "Noreth", "Osfameron",
|
||||
"Robin", "Tanamil", "Tanamoril", "Tanaqui", "Ynen", "Ynynen"
|
||||
};
|
||||
static void fill(char *buf, size_t buflen) {
|
||||
static const char *const names[22] = {
|
||||
"Alhammitt", "Biffa", "Cennoreth", "Dastgandlen", "Enblith",
|
||||
"Fenna", "Gull", "Hern", "Hildrida", "Kankredin",
|
||||
"Kialan", "Lenina", "Manaliabrid", "Mayelbridwen", "Noreth",
|
||||
"Osfameron", "Robin", "Tanamil", "Tanamoril", "Tanaqui",
|
||||
"Ynen", "Ynynen"};
|
||||
|
||||
const char *name;
|
||||
size_t len;
|
||||
const char *name;
|
||||
size_t len;
|
||||
|
||||
while (buflen > 4) {
|
||||
name = names[random()%22];
|
||||
len = strlen(name);
|
||||
if (len < buflen) {
|
||||
strcpy(buf, name);
|
||||
buf += len;
|
||||
buflen -= len;
|
||||
if (buflen > 1) {
|
||||
*buf = ' ';
|
||||
buf++;
|
||||
buflen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (buflen > 1) {
|
||||
*buf = '.';
|
||||
buf++;
|
||||
buflen--;
|
||||
}
|
||||
*buf = 0;
|
||||
while (buflen > 4) {
|
||||
name = names[random() % 22];
|
||||
len = strlen(name);
|
||||
if (len < buflen) {
|
||||
strcpy(buf, name);
|
||||
buf += len;
|
||||
buflen -= len;
|
||||
if (buflen > 1) {
|
||||
*buf = ' ';
|
||||
buf++;
|
||||
buflen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (buflen > 1) {
|
||||
*buf = '.';
|
||||
buf++;
|
||||
buflen--;
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
prepwords(void)
|
||||
{
|
||||
srandom(16581);
|
||||
fill(word4050, sizeof(word4050));
|
||||
fill(word16320, sizeof(word16320));
|
||||
fill(word65500, sizeof(word65500));
|
||||
static void prepwords(void) {
|
||||
srandom(16581);
|
||||
fill(word4050, sizeof(word4050));
|
||||
fill(word16320, sizeof(word16320));
|
||||
fill(word65500, sizeof(word65500));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// execing/checking
|
||||
|
||||
static
|
||||
void
|
||||
try(const char *first, ...)
|
||||
{
|
||||
const char *args[20];
|
||||
const char *s;
|
||||
va_list ap;
|
||||
int num;
|
||||
static void try(const char *first, ...) {
|
||||
const char *args[20];
|
||||
const char *s;
|
||||
va_list ap;
|
||||
int num;
|
||||
|
||||
assert(first != NULL);
|
||||
args[0] = _PATH_MYSELF;
|
||||
args[1] = first;
|
||||
num = 2;
|
||||
assert(first != NULL);
|
||||
args[0] = _PATH_MYSELF;
|
||||
args[1] = first;
|
||||
num = 2;
|
||||
|
||||
va_start(ap, first);
|
||||
while (1) {
|
||||
s = va_arg(ap, const char *);
|
||||
if (s == NULL) {
|
||||
break;
|
||||
}
|
||||
assert(num < 20);
|
||||
args[num++] = s;
|
||||
}
|
||||
assert(num < 20);
|
||||
args[num] = NULL;
|
||||
execv(_PATH_MYSELF, (char **)args);
|
||||
err(1, "execv");
|
||||
va_start(ap, first);
|
||||
while (1) {
|
||||
s = va_arg(ap, const char *);
|
||||
if (s == NULL) {
|
||||
break;
|
||||
}
|
||||
assert(num < 20);
|
||||
args[num++] = s;
|
||||
}
|
||||
assert(num < 20);
|
||||
args[num] = NULL;
|
||||
execv(_PATH_MYSELF, (char **)args);
|
||||
err(1, "execv");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
trymany(int num, const char *word)
|
||||
{
|
||||
const char *args[num+2];
|
||||
int i;
|
||||
static void trymany(int num, const char *word) {
|
||||
const char *args[num + 2];
|
||||
int i;
|
||||
|
||||
args[0] = _PATH_MYSELF;
|
||||
for (i=0; i<num; i++) {
|
||||
args[i+1] = word;
|
||||
}
|
||||
args[num+1] = NULL;
|
||||
execv(_PATH_MYSELF, (char **)args);
|
||||
err(1, "execv");
|
||||
args[0] = _PATH_MYSELF;
|
||||
for (i = 0; i < num; i++) {
|
||||
args[i + 1] = word;
|
||||
}
|
||||
args[num + 1] = NULL;
|
||||
execv(_PATH_MYSELF, (char **)args);
|
||||
err(1, "execv");
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
check(int argc, char *argv[], const char *first, ...)
|
||||
{
|
||||
const char *s;
|
||||
va_list ap;
|
||||
int pos;
|
||||
static int check(int argc, char *argv[], const char *first, ...) {
|
||||
const char *s;
|
||||
va_list ap;
|
||||
int pos;
|
||||
|
||||
pos = 1;
|
||||
va_start(ap, first);
|
||||
s = first;
|
||||
while (s != NULL) {
|
||||
if (pos == argc) {
|
||||
/* not enough args */
|
||||
return 0;
|
||||
}
|
||||
assert(pos < argc);
|
||||
if (argv[pos] == NULL) {
|
||||
/* woops */
|
||||
warnx("argv[%d] is null but argc is %d", pos, argc);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[pos], s) != 0) {
|
||||
/* does not match */
|
||||
return 0;
|
||||
}
|
||||
s = va_arg(ap, const char *);
|
||||
pos++;
|
||||
}
|
||||
if (pos != argc) {
|
||||
/* too many args */
|
||||
return 0;
|
||||
}
|
||||
if (argv[pos] != NULL) {
|
||||
warnx("argv[argc] is not null");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
pos = 1;
|
||||
va_start(ap, first);
|
||||
s = first;
|
||||
while (s != NULL) {
|
||||
if (pos == argc) {
|
||||
/* not enough args */
|
||||
return 0;
|
||||
}
|
||||
assert(pos < argc);
|
||||
if (argv[pos] == NULL) {
|
||||
/* woops */
|
||||
warnx("argv[%d] is null but argc is %d", pos, argc);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[pos], s) != 0) {
|
||||
/* does not match */
|
||||
return 0;
|
||||
}
|
||||
s = va_arg(ap, const char *);
|
||||
pos++;
|
||||
}
|
||||
if (pos != argc) {
|
||||
/* too many args */
|
||||
return 0;
|
||||
}
|
||||
if (argv[pos] != NULL) {
|
||||
warnx("argv[argc] is not null");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
checkmany(int argc, char *argv[], int num, const char *word)
|
||||
{
|
||||
int i;
|
||||
static int checkmany(int argc, char *argv[], int num, const char *word) {
|
||||
int i;
|
||||
|
||||
if (argc != num + 1) {
|
||||
/* wrong number of args */
|
||||
return 0;
|
||||
}
|
||||
for (i=1; i<argc; i++) {
|
||||
if (strcmp(argv[i], word) != 0) {
|
||||
/* doesn't match */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
if (argc != num + 1) {
|
||||
/* wrong number of args */
|
||||
return 0;
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], word) != 0) {
|
||||
/* doesn't match */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// test driver
|
||||
|
||||
static
|
||||
void
|
||||
dumpargs(int argc, char *argv[])
|
||||
{
|
||||
const char *s;
|
||||
int i;
|
||||
static void dumpargs(int argc, char *argv[]) {
|
||||
const char *s;
|
||||
int i;
|
||||
|
||||
warnx("%d args", argc);
|
||||
warnx("argv[0]: %s", argv[0]);
|
||||
for (i=1; i<=argc; i++) {
|
||||
s = argv[i];
|
||||
if (s == NULL) {
|
||||
warnx("argv[%d]: is null", i);
|
||||
}
|
||||
else if (!strcmp(s, word8)) {
|
||||
warnx("argv[%d] is word8", i);
|
||||
}
|
||||
else if (!strcmp(s, word4050)) {
|
||||
warnx("argv[%d] is word4050", i);
|
||||
}
|
||||
else if (!strcmp(s, word16320)) {
|
||||
warnx("argv[%d] is word16320", i);
|
||||
}
|
||||
else if (!strcmp(s, word65500)) {
|
||||
warnx("argv[%d] is word65500", i);
|
||||
}
|
||||
else if (strlen(s) < 72) {
|
||||
warnx("argv[%d]: %s", i, s);
|
||||
}
|
||||
else {
|
||||
warnx("argv[%d] is %zu bytes, begins %.64s",
|
||||
i, strlen(s), s);
|
||||
}
|
||||
}
|
||||
warnx("%d args", argc);
|
||||
warnx("argv[0]: %s", argv[0]);
|
||||
for (i = 1; i <= argc; i++) {
|
||||
s = argv[i];
|
||||
if (s == NULL) {
|
||||
warnx("argv[%d]: is null", i);
|
||||
} else if (!strcmp(s, word8)) {
|
||||
warnx("argv[%d] is word8", i);
|
||||
} else if (!strcmp(s, word4050)) {
|
||||
warnx("argv[%d] is word4050", i);
|
||||
} else if (!strcmp(s, word16320)) {
|
||||
warnx("argv[%d] is word16320", i);
|
||||
} else if (!strcmp(s, word65500)) {
|
||||
warnx("argv[%d] is word65500", i);
|
||||
} else if (strlen(s) < 72) {
|
||||
warnx("argv[%d]: %s", i, s);
|
||||
} else {
|
||||
warnx("argv[%d] is %zu bytes, begins %.64s", i, strlen(s), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 0) {
|
||||
err(1, "argc is negative!?");
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 0) {
|
||||
err(1, "argc is negative!?");
|
||||
}
|
||||
|
||||
prepwords();
|
||||
assert(strlen(word8) == 8);
|
||||
assert(strlen(word4050) == 4050);
|
||||
assert(strlen(word16320) == 16320);
|
||||
assert(strlen(word65500) == 65500);
|
||||
prepwords();
|
||||
assert(strlen(word8) == 8);
|
||||
assert(strlen(word4050) == 4050);
|
||||
assert(strlen(word16320) == 16320);
|
||||
assert(strlen(word65500) == 65500);
|
||||
|
||||
assert(ARG_MAX >= 65536);
|
||||
assert(ARG_MAX >= 65536);
|
||||
|
||||
if (argv == NULL || argc == 0 || argc == 1) {
|
||||
/* no args -- start the test */
|
||||
warnx("Starting.");
|
||||
if (argv == NULL || argc == 0 || argc == 1) {
|
||||
/* no args -- start the test */
|
||||
warnx("Starting.");
|
||||
|
||||
/*
|
||||
* 1. Should always fit no matter what.
|
||||
*/
|
||||
warnx("1. Execing with one 8-letter word.");
|
||||
try(word8, NULL);
|
||||
}
|
||||
else if (check(argc, argv, word8, NULL)) {
|
||||
/*
|
||||
* 2. Fits in one page.
|
||||
*/
|
||||
warnx("2. Execing with one 4050-letter word.");
|
||||
try(word4050, NULL);
|
||||
}
|
||||
else if (check(argc, argv, word4050, NULL)) {
|
||||
/*
|
||||
* 3. Requires two pages but each word fits on a page.
|
||||
*/
|
||||
warnx("3. Execing with two 4050-letter words.");
|
||||
try(word4050, word4050, NULL);
|
||||
}
|
||||
else if (check(argc, argv, word4050, word4050, NULL)) {
|
||||
/*
|
||||
* 4. Requires the full 64K argv buffer, in large
|
||||
* chunks, with a little space for slop. Each word
|
||||
* fits on a page though. With null terminators and
|
||||
* 4-byte pointers the size is 4085*16 = 65360, and
|
||||
* with 8-byte pointers it would become 65424.
|
||||
*
|
||||
* Don't forget that argv[0] will be another 21 or 25
|
||||
* bytes and some implementations may reasonably need
|
||||
* to stash an ending NULL in the buffer too.
|
||||
*/
|
||||
warnx("4. Execing with 16 4050-letter words.");
|
||||
try(word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050,
|
||||
NULL);
|
||||
}
|
||||
else if (check(argc, argv,
|
||||
word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050,
|
||||
NULL)) {
|
||||
/*
|
||||
* 5. Requires more than one page for a single word.
|
||||
*/
|
||||
warnx("5. Execing with one 16320-letter word.");
|
||||
try(word16320, NULL);
|
||||
}
|
||||
else if (check(argc, argv, word16320, NULL)) {
|
||||
/*
|
||||
* 6. Ditto but makes sure it works with two of them.
|
||||
*/
|
||||
warnx("6. Execing with two 16320-letter words.");
|
||||
try(word16320, word16320, NULL);
|
||||
}
|
||||
else if (check(argc, argv, word16320, word16320, NULL)) {
|
||||
/*
|
||||
* 7. Requires the full 64K argv buffer.
|
||||
*/
|
||||
warnx("7. Execing with four 16320-letter words.");
|
||||
try(word16320, word16320, word16320, word16320,
|
||||
NULL);
|
||||
}
|
||||
else if (check(argc, argv, word16320, word16320,
|
||||
word16320, word16320, NULL)) {
|
||||
/*
|
||||
* 8. Also requires the full 64K argv buffer, but with
|
||||
* only one huge word.
|
||||
*/
|
||||
warnx("8. Execing with one 65500-letter word.");
|
||||
try(word65500, NULL);
|
||||
}
|
||||
else if (check(argc, argv, word65500, NULL)) {
|
||||
/*
|
||||
* 9. This fits on one page. Given 4-byte pointers,
|
||||
* (8+1+4)*300 = 3900. With 8-byte pointers, it
|
||||
* doesn't, but we aren't doing that. (Update this if
|
||||
* we ever move to a 64-bit platform.)
|
||||
*/
|
||||
assert((8+1+sizeof(char *))*300 < 4096);
|
||||
warnx("9. Execing with 300 8-letter words.");
|
||||
trymany(300, word8);
|
||||
}
|
||||
else if (checkmany(argc, argv, 300, word8)) {
|
||||
/*
|
||||
* 1. Should always fit no matter what.
|
||||
*/
|
||||
warnx("1. Execing with one 8-letter word.");
|
||||
try(word8, NULL);
|
||||
} else if (check(argc, argv, word8, NULL)) {
|
||||
/*
|
||||
* 2. Fits in one page.
|
||||
*/
|
||||
warnx("2. Execing with one 4050-letter word.");
|
||||
try(word4050, NULL);
|
||||
} else if (check(argc, argv, word4050, NULL)) {
|
||||
/*
|
||||
* 3. Requires two pages but each word fits on a page.
|
||||
*/
|
||||
warnx("3. Execing with two 4050-letter words.");
|
||||
try(word4050, word4050, NULL);
|
||||
} else if (check(argc, argv, word4050, word4050, NULL)) {
|
||||
/*
|
||||
* 4. Requires the full 64K argv buffer, in large
|
||||
* chunks, with a little space for slop. Each word
|
||||
* fits on a page though. With null terminators and
|
||||
* 4-byte pointers the size is 4085*16 = 65360, and
|
||||
* with 8-byte pointers it would become 65424.
|
||||
*
|
||||
* Don't forget that argv[0] will be another 21 or 25
|
||||
* bytes and some implementations may reasonably need
|
||||
* to stash an ending NULL in the buffer too.
|
||||
*/
|
||||
warnx("4. Execing with 16 4050-letter words.");
|
||||
try(word4050, word4050, word4050, word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, NULL);
|
||||
} else if (check(argc, argv, word4050, word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050, word4050, word4050,
|
||||
word4050, word4050, word4050, word4050, word4050, NULL)) {
|
||||
/*
|
||||
* 5. Requires more than one page for a single word.
|
||||
*/
|
||||
warnx("5. Execing with one 16320-letter word.");
|
||||
try(word16320, NULL);
|
||||
} else if (check(argc, argv, word16320, NULL)) {
|
||||
/*
|
||||
* 6. Ditto but makes sure it works with two of them.
|
||||
*/
|
||||
warnx("6. Execing with two 16320-letter words.");
|
||||
try(word16320, word16320, NULL);
|
||||
} else if (check(argc, argv, word16320, word16320, NULL)) {
|
||||
/*
|
||||
* 7. Requires the full 64K argv buffer.
|
||||
*/
|
||||
warnx("7. Execing with four 16320-letter words.");
|
||||
try(word16320, word16320, word16320, word16320, NULL);
|
||||
} else if (check(argc, argv, word16320, word16320, word16320, word16320,
|
||||
NULL)) {
|
||||
/*
|
||||
* 8. Also requires the full 64K argv buffer, but with
|
||||
* only one huge word.
|
||||
*/
|
||||
warnx("8. Execing with one 65500-letter word.");
|
||||
try(word65500, NULL);
|
||||
} else if (check(argc, argv, word65500, NULL)) {
|
||||
/*
|
||||
* 9. This fits on one page. Given 4-byte pointers,
|
||||
* (8+1+4)*300 = 3900. With 8-byte pointers, it
|
||||
* doesn't, but we aren't doing that. (Update this if
|
||||
* we ever move to a 64-bit platform.)
|
||||
*/
|
||||
assert((8 + 1 + sizeof(char *)) * 300 < 4096);
|
||||
warnx("9. Execing with 300 8-letter words.");
|
||||
trymany(300, word8);
|
||||
} else if (checkmany(argc, argv, 300, word8)) {
|
||||
#if 1 /* enforce the full size */
|
||||
/*
|
||||
* 10. This requires the full 64K argv buffer.
|
||||
* With 4-byte pointers, (8+1+4)*5020 = 65260.
|
||||
* It also doesn't fit with 8-byte pointers.
|
||||
*
|
||||
* XXX for the time being, we'll allow less efficient
|
||||
* implementations that use two pointers per word.
|
||||
* Hence, (8+1+4+4)*3850 = 65450.
|
||||
*/
|
||||
assert((8+1+sizeof(char *))*5020 < 65536);
|
||||
assert((8+1+2*sizeof(char *))*3850 < 65536);
|
||||
warnx("10. Execing with 3850 8-letter words.");
|
||||
trymany(3850, word8);
|
||||
}
|
||||
else if (checkmany(argc, argv, 3850, word8)) {
|
||||
/*
|
||||
* 10. This requires the full 64K argv buffer.
|
||||
* With 4-byte pointers, (8+1+4)*5020 = 65260.
|
||||
* It also doesn't fit with 8-byte pointers.
|
||||
*
|
||||
* XXX for the time being, we'll allow less efficient
|
||||
* implementations that use two pointers per word.
|
||||
* Hence, (8+1+4+4)*3850 = 65450.
|
||||
*/
|
||||
assert((8 + 1 + sizeof(char *)) * 5020 < 65536);
|
||||
assert((8 + 1 + 2 * sizeof(char *)) * 3850 < 65536);
|
||||
warnx("10. Execing with 3850 8-letter words.");
|
||||
trymany(3850, word8);
|
||||
} else if (checkmany(argc, argv, 3850, word8)) {
|
||||
#else
|
||||
/*
|
||||
* 10a. This requires more than one page using small
|
||||
* words. With 4-byte pointers, (8+1+4)*1000 = 13000.
|
||||
*/
|
||||
warnx("10. Execing with 1000 8-letter words.");
|
||||
trymany(1000, word8);
|
||||
}
|
||||
else if (checkmany(argc, argv, 1000, word8)) {
|
||||
/*
|
||||
* 10a. This requires more than one page using small
|
||||
* words. With 4-byte pointers, (8+1+4)*1000 = 13000.
|
||||
*/
|
||||
warnx("10. Execing with 1000 8-letter words.");
|
||||
trymany(1000, word8);
|
||||
} else if (checkmany(argc, argv, 1000, word8)) {
|
||||
#endif
|
||||
warnx("Complete.");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
warnx("Received unknown/unexpected args:");
|
||||
dumpargs(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
warnx("Complete.");
|
||||
return 0;
|
||||
} else {
|
||||
warnx("Received unknown/unexpected args:");
|
||||
dumpargs(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,64 +44,60 @@
|
||||
|
||||
static char buffer[8192 + 1];
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *filename;
|
||||
char *s;
|
||||
size_t i, size, chunksize, offset;
|
||||
ssize_t len;
|
||||
int fd;
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *filename;
|
||||
char *s;
|
||||
size_t i, size, chunksize, offset;
|
||||
ssize_t len;
|
||||
int fd;
|
||||
|
||||
if (argc != 3) {
|
||||
warnx("Usage: bigfile <filename> <size>");
|
||||
errx(1, " or: bigfile <filename> <size>/<chunksize>");
|
||||
}
|
||||
if (argc != 3) {
|
||||
warnx("Usage: bigfile <filename> <size>");
|
||||
errx(1, " or: bigfile <filename> <size>/<chunksize>");
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
s = strchr(argv[2], '/');
|
||||
if (s != NULL) {
|
||||
*s++ = 0;
|
||||
chunksize = atoi(s);
|
||||
if (chunksize >= sizeof(buffer)) {
|
||||
chunksize = sizeof(buffer) - 1;
|
||||
}
|
||||
if (chunksize == 0) {
|
||||
errx(1, "Really?");
|
||||
}
|
||||
}
|
||||
else {
|
||||
chunksize = 10;
|
||||
}
|
||||
size = atoi(argv[2]);
|
||||
filename = argv[1];
|
||||
s = strchr(argv[2], '/');
|
||||
if (s != NULL) {
|
||||
*s++ = 0;
|
||||
chunksize = atoi(s);
|
||||
if (chunksize >= sizeof(buffer)) {
|
||||
chunksize = sizeof(buffer) - 1;
|
||||
}
|
||||
if (chunksize == 0) {
|
||||
errx(1, "Really?");
|
||||
}
|
||||
} else {
|
||||
chunksize = 10;
|
||||
}
|
||||
size = atoi(argv[2]);
|
||||
|
||||
/* round size up */
|
||||
size = ((size + chunksize - 1) / chunksize) * chunksize;
|
||||
/* round size up */
|
||||
size = ((size + chunksize - 1) / chunksize) * chunksize;
|
||||
|
||||
printf("Creating a file of size %d in %d-byte chunks\n",
|
||||
size, chunksize);
|
||||
printf("Creating a file of size %d in %d-byte chunks\n", size, chunksize);
|
||||
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", filename);
|
||||
}
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", filename);
|
||||
}
|
||||
|
||||
i=0;
|
||||
while (i<size) {
|
||||
snprintf(buffer, sizeof(buffer), "%d\n", i);
|
||||
if (strlen(buffer) < chunksize) {
|
||||
offset = chunksize - strlen(buffer);
|
||||
memmove(buffer + offset, buffer, strlen(buffer)+1);
|
||||
memset(buffer, ' ', offset);
|
||||
}
|
||||
len = write(fd, buffer, strlen(buffer));
|
||||
if (len<0) {
|
||||
err(1, "%s: write", filename);
|
||||
}
|
||||
i += len;
|
||||
}
|
||||
i = 0;
|
||||
while (i < size) {
|
||||
snprintf(buffer, sizeof(buffer), "%d\n", i);
|
||||
if (strlen(buffer) < chunksize) {
|
||||
offset = chunksize - strlen(buffer);
|
||||
memmove(buffer + offset, buffer, strlen(buffer) + 1);
|
||||
memset(buffer, ' ', offset);
|
||||
}
|
||||
len = write(fd, buffer, strlen(buffer));
|
||||
if (len < 0) {
|
||||
err(1, "%s: write", filename);
|
||||
}
|
||||
i += len;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -54,186 +54,145 @@
|
||||
*/
|
||||
#define DIM 64
|
||||
|
||||
static int m1[DIM*DIM], m2[DIM*DIM], m3[DIM*DIM], m4[DIM*DIM];
|
||||
static int m1[DIM * DIM], m2[DIM * DIM], m3[DIM * DIM], m4[DIM * DIM];
|
||||
static const int right[BRANCHES] = {
|
||||
536763422,
|
||||
478946723,
|
||||
375722852,
|
||||
369910585,
|
||||
328220902,
|
||||
62977821,
|
||||
536763422, 478946723, 375722852, 369910585, 328220902, 62977821,
|
||||
};
|
||||
static unsigned failures;
|
||||
|
||||
static
|
||||
void
|
||||
init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
static void init(void) {
|
||||
unsigned i, j;
|
||||
|
||||
srandom(73771);
|
||||
for (i=0; i<DIM; i++) {
|
||||
for (j=0; j<DIM; j++) {
|
||||
m1[i*DIM+j] = random() % 11 - 5;
|
||||
}
|
||||
}
|
||||
srandom(73771);
|
||||
for (i = 0; i < DIM; i++) {
|
||||
for (j = 0; j < DIM; j++) {
|
||||
m1[i * DIM + j] = random() % 11 - 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
add(int *x, const int *a, const int *b)
|
||||
{
|
||||
unsigned i, j;
|
||||
static void add(int *x, const int *a, const int *b) {
|
||||
unsigned i, j;
|
||||
|
||||
for (i=0; i<DIM; i++) {
|
||||
for (j=0; j<DIM; j++) {
|
||||
x[i*DIM+j] = a[i*DIM+j] + b[i*DIM+j];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < DIM; i++) {
|
||||
for (j = 0; j < DIM; j++) {
|
||||
x[i * DIM + j] = a[i * DIM + j] + b[i * DIM + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mul(int *x, const int *a, const int *b)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
static void mul(int *x, const int *a, const int *b) {
|
||||
unsigned i, j, k;
|
||||
|
||||
for (i=0; i<DIM; i++) {
|
||||
for (j=0; j<DIM; j++) {
|
||||
x[i*DIM+j] = 0;
|
||||
for (k=0; k<DIM; k++) {
|
||||
x[i*DIM+j] += a[i*DIM+k] * b[k*DIM+j];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < DIM; i++) {
|
||||
for (j = 0; j < DIM; j++) {
|
||||
x[i * DIM + j] = 0;
|
||||
for (k = 0; k < DIM; k++) {
|
||||
x[i * DIM + j] += a[i * DIM + k] * b[k * DIM + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
scale(int *x, const int *a, int b)
|
||||
{
|
||||
unsigned i, j;
|
||||
static void scale(int *x, const int *a, int b) {
|
||||
unsigned i, j;
|
||||
|
||||
for (i=0; i<DIM; i++) {
|
||||
for (j=0; j<DIM; j++) {
|
||||
x[i*DIM+j] = a[i*DIM+j] / b;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < DIM; i++) {
|
||||
for (j = 0; j < DIM; j++) {
|
||||
x[i * DIM + j] = a[i * DIM + j] / b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
grind(void)
|
||||
{
|
||||
/*
|
||||
* compute: m2 = m1*m1, m3 = m2+m1, m4 = m3*m3, m1 = m4 / 2
|
||||
*/
|
||||
mul(m2, m1, m1);
|
||||
add(m3, m2, m1);
|
||||
mul(m4, m3, m3);
|
||||
scale(m1, m4, 2);
|
||||
static void grind(void) {
|
||||
/*
|
||||
* compute: m2 = m1*m1, m3 = m2+m1, m4 = m3*m3, m1 = m4 / 2
|
||||
*/
|
||||
mul(m2, m1, m1);
|
||||
add(m3, m2, m1);
|
||||
mul(m4, m3, m3);
|
||||
scale(m1, m4, 2);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
trace(void)
|
||||
{
|
||||
unsigned i;
|
||||
int val = 0;
|
||||
static int trace(void) {
|
||||
unsigned i;
|
||||
int val = 0;
|
||||
|
||||
for (i=0; i<DIM; i++) {
|
||||
val += m1[i*DIM+i];
|
||||
}
|
||||
while (val < 0) {
|
||||
val += 0x20000000;
|
||||
}
|
||||
return val % 0x20000000;
|
||||
for (i = 0; i < DIM; i++) {
|
||||
val += m1[i * DIM + i];
|
||||
}
|
||||
while (val < 0) {
|
||||
val += 0x20000000;
|
||||
}
|
||||
return val % 0x20000000;
|
||||
}
|
||||
|
||||
static
|
||||
pid_t
|
||||
dofork(void)
|
||||
{
|
||||
pid_t pid;
|
||||
static pid_t dofork(void) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
warn("fork");
|
||||
}
|
||||
return pid;
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
warn("fork");
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dowait(pid_t pid)
|
||||
{
|
||||
int status;
|
||||
static void dowait(pid_t pid) {
|
||||
int status;
|
||||
|
||||
if (pid == -1) {
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(failures);
|
||||
}
|
||||
else {
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("waitpid(%d)", pid);
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d: signal %d", pid, WTERMSIG(status));
|
||||
}
|
||||
else if (WEXITSTATUS(status) > 0) {
|
||||
failures += WEXITSTATUS(status);
|
||||
}
|
||||
}
|
||||
if (pid == -1) {
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(failures);
|
||||
} else {
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("waitpid(%d)", pid);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d: signal %d", pid, WTERMSIG(status));
|
||||
} else if (WEXITSTATUS(status) > 0) {
|
||||
failures += WEXITSTATUS(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dotest(void)
|
||||
{
|
||||
unsigned i, me;
|
||||
pid_t pids[BRANCHES];
|
||||
int t;
|
||||
char msg[128];
|
||||
static void dotest(void) {
|
||||
unsigned i, me;
|
||||
pid_t pids[BRANCHES];
|
||||
int t;
|
||||
char msg[128];
|
||||
|
||||
me = 0;
|
||||
for (i=0; i<BRANCHES; i++) {
|
||||
pids[i] = dofork();
|
||||
if (pids[i] == 0) {
|
||||
me += 1U<<i;
|
||||
}
|
||||
grind();
|
||||
t = trace();
|
||||
if (t == right[i]) {
|
||||
snprintf(msg, sizeof(msg),
|
||||
"Stage %u #%u done: %d\n", i, me, trace());
|
||||
}
|
||||
else {
|
||||
snprintf(msg, sizeof(msg),
|
||||
"Stage %u #%u FAILED: got %d, expected %d\n",
|
||||
i, me, t, right[i]);
|
||||
failures++;
|
||||
}
|
||||
(void)write(STDOUT_FILENO, msg, strlen(msg));
|
||||
}
|
||||
me = 0;
|
||||
for (i = 0; i < BRANCHES; i++) {
|
||||
pids[i] = dofork();
|
||||
if (pids[i] == 0) {
|
||||
me += 1U << i;
|
||||
}
|
||||
grind();
|
||||
t = trace();
|
||||
if (t == right[i]) {
|
||||
snprintf(msg, sizeof(msg), "Stage %u #%u done: %d\n", i, me, trace());
|
||||
} else {
|
||||
snprintf(msg, sizeof(msg), "Stage %u #%u FAILED: got %d, expected %d\n",
|
||||
i, me, t, right[i]);
|
||||
failures++;
|
||||
}
|
||||
(void)write(STDOUT_FILENO, msg, strlen(msg));
|
||||
}
|
||||
|
||||
for (i=BRANCHES; i-- > 0; ) {
|
||||
dowait(pids[i]);
|
||||
}
|
||||
if (failures > 0) {
|
||||
printf("%u failures.\n", failures);
|
||||
}
|
||||
else {
|
||||
printf("Done.\n");
|
||||
}
|
||||
for (i = BRANCHES; i-- > 0;) {
|
||||
dowait(pids[i]);
|
||||
}
|
||||
if (failures > 0) {
|
||||
printf("%u failures.\n", failures);
|
||||
} else {
|
||||
printf("Done.\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
init();
|
||||
dotest();
|
||||
return 0;
|
||||
int main(void) {
|
||||
init();
|
||||
dotest();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -63,208 +63,184 @@
|
||||
#define TESTFILE "bigseekfile"
|
||||
|
||||
static const char *slogans[] = {
|
||||
"QUO USQUE TANDEM ABUTERE CATILINA PATENTIA NOSTRA",
|
||||
"QUEM IN FINEM SESE EFFRENATA IACTABIT AUDACIA"
|
||||
};
|
||||
"QUO USQUE TANDEM ABUTERE CATILINA PATENTIA NOSTRA",
|
||||
"QUEM IN FINEM SESE EFFRENATA IACTABIT AUDACIA"};
|
||||
|
||||
static
|
||||
void
|
||||
write_slogan(int fd, unsigned which, bool failok)
|
||||
{
|
||||
size_t len;
|
||||
ssize_t r;
|
||||
static void write_slogan(int fd, unsigned which, bool failok) {
|
||||
size_t len;
|
||||
ssize_t r;
|
||||
|
||||
len = strlen(slogans[which]);
|
||||
r = write(fd, slogans[which], len);
|
||||
if (r < 0) {
|
||||
if (failok && errno == EFBIG) {
|
||||
return;
|
||||
}
|
||||
err(1, "write");
|
||||
}
|
||||
if (failok) {
|
||||
errx(1, "write: expected failure but wrote %zd bytes", r);
|
||||
}
|
||||
if ((size_t)r != len) {
|
||||
errx(1, "write: result %zd bytes, expected %zu", r, len);
|
||||
}
|
||||
len = strlen(slogans[which]);
|
||||
r = write(fd, slogans[which], len);
|
||||
if (r < 0) {
|
||||
if (failok && errno == EFBIG) {
|
||||
return;
|
||||
}
|
||||
err(1, "write");
|
||||
}
|
||||
if (failok) {
|
||||
errx(1, "write: expected failure but wrote %zd bytes", r);
|
||||
}
|
||||
if ((size_t)r != len) {
|
||||
errx(1, "write: result %zd bytes, expected %zu", r, len);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
check_slogan(int fd, unsigned which)
|
||||
{
|
||||
char buf[256];
|
||||
size_t len;
|
||||
ssize_t r;
|
||||
unsigned i, wrongcount;
|
||||
static void check_slogan(int fd, unsigned which) {
|
||||
char buf[256];
|
||||
size_t len;
|
||||
ssize_t r;
|
||||
unsigned i, wrongcount;
|
||||
|
||||
r = read(fd, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
err(1, "read");
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "read: Unexpected EOF");
|
||||
}
|
||||
r = read(fd, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
err(1, "read");
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "read: Unexpected EOF");
|
||||
}
|
||||
|
||||
/* we should get either a full buffer or the length of the slogan */
|
||||
len = strlen(slogans[which]);
|
||||
if ((size_t)r != sizeof(buf) && (size_t)r != len) {
|
||||
errx(1, "read: result %zd bytes, expected %zu or %zu",
|
||||
r, sizeof(buf), len);
|
||||
}
|
||||
/* we should get either a full buffer or the length of the slogan */
|
||||
len = strlen(slogans[which]);
|
||||
if ((size_t)r != sizeof(buf) && (size_t)r != len) {
|
||||
errx(1, "read: result %zd bytes, expected %zu or %zu", r, sizeof(buf), len);
|
||||
}
|
||||
|
||||
/* slogan should match */
|
||||
if (memcmp(buf, slogans[which], len) != 0) {
|
||||
warnx("read: got wrong data");
|
||||
warnx("expected: %s", slogans[which]);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
errx(1, "found: %s", buf);
|
||||
}
|
||||
/* slogan should match */
|
||||
if (memcmp(buf, slogans[which], len) != 0) {
|
||||
warnx("read: got wrong data");
|
||||
warnx("expected: %s", slogans[which]);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
errx(1, "found: %s", buf);
|
||||
}
|
||||
|
||||
/* bytes past the slogan (if any) should be 0 */
|
||||
wrongcount = 0;
|
||||
for (i=len; i<(size_t)r; i++) {
|
||||
if (buf[i] != 0) {
|
||||
warnx("read: buf[%zu] was 0x%x, expected 0", i,
|
||||
(unsigned char)buf[i]);
|
||||
wrongcount++;
|
||||
}
|
||||
}
|
||||
if (wrongcount > 0) {
|
||||
errx(1, "%u bytes of trash in file", wrongcount);
|
||||
}
|
||||
/* bytes past the slogan (if any) should be 0 */
|
||||
wrongcount = 0;
|
||||
for (i = len; i < (size_t)r; i++) {
|
||||
if (buf[i] != 0) {
|
||||
warnx("read: buf[%zu] was 0x%x, expected 0", i, (unsigned char)buf[i]);
|
||||
wrongcount++;
|
||||
}
|
||||
}
|
||||
if (wrongcount > 0) {
|
||||
errx(1, "%u bytes of trash in file", wrongcount);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
try_reading(int fd)
|
||||
{
|
||||
char buf[16];
|
||||
ssize_t r;
|
||||
static void try_reading(int fd) {
|
||||
char buf[16];
|
||||
ssize_t r;
|
||||
|
||||
r = read(fd, buf, sizeof(buf));
|
||||
if (r == 0) {
|
||||
/* expected EOF */
|
||||
return;
|
||||
}
|
||||
if (r < 0) {
|
||||
err(1, "read");
|
||||
}
|
||||
errx(1, "read: Expected EOF but got %zd bytes", r);
|
||||
r = read(fd, buf, sizeof(buf));
|
||||
if (r == 0) {
|
||||
/* expected EOF */
|
||||
return;
|
||||
}
|
||||
if (r < 0) {
|
||||
err(1, "read");
|
||||
}
|
||||
errx(1, "read: Expected EOF but got %zd bytes", r);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
try_writing(int fd)
|
||||
{
|
||||
write_slogan(fd, 1, true);
|
||||
static void try_writing(int fd) { write_slogan(fd, 1, true); }
|
||||
|
||||
static void dolseek(int fd, off_t pos, int whence, const char *whencestr,
|
||||
off_t expected) {
|
||||
off_t result;
|
||||
|
||||
result = lseek(fd, pos, whence);
|
||||
if (result == -1) {
|
||||
err(1, "lseek(fd, 0x%llx, %s)", pos, whencestr);
|
||||
}
|
||||
if (result != expected) {
|
||||
errx(1,
|
||||
"lseek(fd, 0x%llx, %s): Wrong return value"
|
||||
" (got 0x%llx, expected 0x%llx)",
|
||||
pos, whencestr, result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dolseek(int fd, off_t pos, int whence, const char *whencestr, off_t expected)
|
||||
{
|
||||
off_t result;
|
||||
static void try_seeking(int fd, off_t pos, off_t cursize) {
|
||||
printf("Seeking to (and near) 0x%llx\n", pos);
|
||||
|
||||
result = lseek(fd, pos, whence);
|
||||
if (result == -1) {
|
||||
err(1, "lseek(fd, 0x%llx, %s)", pos, whencestr);
|
||||
}
|
||||
if (result != expected) {
|
||||
errx(1, "lseek(fd, 0x%llx, %s): Wrong return value"
|
||||
" (got 0x%llx, expected 0x%llx)", pos, whencestr,
|
||||
result, expected);
|
||||
}
|
||||
/* Go to the place. */
|
||||
dolseek(fd, pos, SEEK_SET, "SEEK_SET", pos);
|
||||
|
||||
/* Go to where we already are. */
|
||||
dolseek(fd, 0, SEEK_CUR, "SEEK_CUR", pos);
|
||||
|
||||
if (pos >= 10) {
|
||||
/* Back up a little. */
|
||||
dolseek(fd, -10, SEEK_CUR, "SEEK_CUR", pos - 10);
|
||||
|
||||
/* Forward a little. */
|
||||
dolseek(fd, 20, SEEK_CUR, "SEEK_CUR", pos + 10);
|
||||
} else {
|
||||
/* Just forward a little. */
|
||||
dolseek(fd, 10, SEEK_CUR, "SEEK_CUR", pos + 10);
|
||||
}
|
||||
|
||||
/* Via SEEK_END. */
|
||||
dolseek(fd, pos, SEEK_END, "SEEK_END", pos + cursize);
|
||||
|
||||
/* Go back to the exact place. */
|
||||
dolseek(fd, pos, SEEK_SET, "SEEK_SET", pos);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
try_seeking(int fd, off_t pos, off_t cursize)
|
||||
{
|
||||
printf("Seeking to (and near) 0x%llx\n", pos);
|
||||
int main(void) {
|
||||
off_t cursize;
|
||||
int fd;
|
||||
|
||||
/* Go to the place. */
|
||||
dolseek(fd, pos, SEEK_SET, "SEEK_SET", pos);
|
||||
printf("Creating file...\n");
|
||||
fd = open(TESTFILE, O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", TESTFILE);
|
||||
}
|
||||
|
||||
/* Go to where we already are. */
|
||||
dolseek(fd, 0, SEEK_CUR, "SEEK_CUR", pos);
|
||||
printf("Writing something at offset 0\n");
|
||||
write_slogan(fd, 0, false);
|
||||
cursize = strlen(slogans[0]);
|
||||
|
||||
if (pos >= 10) {
|
||||
/* Back up a little. */
|
||||
dolseek(fd, -10, SEEK_CUR, "SEEK_CUR", pos - 10);
|
||||
try_seeking(fd, (off_t)0x1000LL, cursize);
|
||||
|
||||
/* Forward a little. */
|
||||
dolseek(fd, 20, SEEK_CUR, "SEEK_CUR", pos + 10);
|
||||
}
|
||||
else {
|
||||
/* Just forward a little. */
|
||||
dolseek(fd, 10, SEEK_CUR, "SEEK_CUR", pos + 10);
|
||||
}
|
||||
printf("Writing something else\n");
|
||||
write_slogan(fd, 1, false);
|
||||
cursize = (off_t)0x1000LL + strlen(slogans[1]);
|
||||
|
||||
/* Via SEEK_END. */
|
||||
dolseek(fd, pos, SEEK_END, "SEEK_END", pos + cursize);
|
||||
try_seeking(fd, (off_t)0, cursize);
|
||||
|
||||
/* Go back to the exact place. */
|
||||
dolseek(fd, pos, SEEK_SET, "SEEK_SET", pos);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
off_t cursize;
|
||||
int fd;
|
||||
|
||||
printf("Creating file...\n");
|
||||
fd = open(TESTFILE, O_RDWR|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", TESTFILE);
|
||||
}
|
||||
|
||||
printf("Writing something at offset 0\n");
|
||||
write_slogan(fd, 0, false);
|
||||
cursize = strlen(slogans[0]);
|
||||
|
||||
try_seeking(fd, (off_t)0x1000LL, cursize);
|
||||
|
||||
printf("Writing something else\n");
|
||||
write_slogan(fd, 1, false);
|
||||
cursize = (off_t)0x1000LL + strlen(slogans[1]);
|
||||
|
||||
try_seeking(fd, (off_t)0, cursize);
|
||||
|
||||
/* If seek is totally bust, this will fail. */
|
||||
printf("Checking what we wrote\n");
|
||||
check_slogan(fd, 0);
|
||||
|
||||
try_seeking(fd, (off_t)0x1000LL, cursize);
|
||||
printf("Checking the other thing we wrote\n");
|
||||
check_slogan(fd, 1);
|
||||
|
||||
try_seeking(fd, (off_t)0x20LL, cursize);
|
||||
try_seeking(fd, (off_t)0x7fffffffLL, cursize);
|
||||
try_seeking(fd, (off_t)0x80000000LL, cursize);
|
||||
try_seeking(fd, (off_t)0x80000020LL, cursize);
|
||||
try_seeking(fd, (off_t)0x100000000LL, cursize);
|
||||
try_seeking(fd, (off_t)0x100000020LL, cursize);
|
||||
try_seeking(fd, (off_t)0x180000000LL, cursize);
|
||||
try_seeking(fd, (off_t)0x180000020LL, cursize);
|
||||
|
||||
printf("Now trying to read (should get EOF)\n");
|
||||
try_reading(fd);
|
||||
|
||||
printf("Now trying to write (should get EFBIG)\n");
|
||||
try_writing(fd);
|
||||
|
||||
try_seeking(fd, (off_t)0x100000000LL, cursize);
|
||||
|
||||
/* If seek truncates to 32 bits, this might read the slogan instead */
|
||||
printf("Trying to read again (should get EOF)\n");
|
||||
try_reading(fd);
|
||||
|
||||
printf("Passed.\n");
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return 0;
|
||||
/* If seek is totally bust, this will fail. */
|
||||
printf("Checking what we wrote\n");
|
||||
check_slogan(fd, 0);
|
||||
|
||||
try_seeking(fd, (off_t)0x1000LL, cursize);
|
||||
printf("Checking the other thing we wrote\n");
|
||||
check_slogan(fd, 1);
|
||||
|
||||
try_seeking(fd, (off_t)0x20LL, cursize);
|
||||
try_seeking(fd, (off_t)0x7fffffffLL, cursize);
|
||||
try_seeking(fd, (off_t)0x80000000LL, cursize);
|
||||
try_seeking(fd, (off_t)0x80000020LL, cursize);
|
||||
try_seeking(fd, (off_t)0x100000000LL, cursize);
|
||||
try_seeking(fd, (off_t)0x100000020LL, cursize);
|
||||
try_seeking(fd, (off_t)0x180000000LL, cursize);
|
||||
try_seeking(fd, (off_t)0x180000020LL, cursize);
|
||||
|
||||
printf("Now trying to read (should get EOF)\n");
|
||||
try_reading(fd);
|
||||
|
||||
printf("Now trying to write (should get EFBIG)\n");
|
||||
try_writing(fd);
|
||||
|
||||
try_seeking(fd, (off_t)0x100000000LL, cursize);
|
||||
|
||||
/* If seek truncates to 32 bits, this might read the slogan instead */
|
||||
printf("Trying to read again (should get EOF)\n");
|
||||
try_reading(fd);
|
||||
|
||||
printf("Passed.\n");
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -32,173 +32,145 @@ static unsigned touchpages;
|
||||
/* when touching pages, the extent to which we favor the middle of the range */
|
||||
static unsigned bias;
|
||||
|
||||
static void moremem(void) {
|
||||
static unsigned totalpages;
|
||||
|
||||
static
|
||||
void
|
||||
moremem(void)
|
||||
{
|
||||
static unsigned totalpages;
|
||||
void *ptr;
|
||||
unsigned i;
|
||||
|
||||
void *ptr;
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<allocs; i++) {
|
||||
ptr = sbrk(PAGE_SIZE);
|
||||
if (ptr == (void *)-1) {
|
||||
err(1, "After %u pages: sbrk", totalpages);
|
||||
}
|
||||
totalpages++;
|
||||
lastpage = ptr;
|
||||
if (firstpage == NULL) {
|
||||
firstpage = ptr;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < allocs; i++) {
|
||||
ptr = sbrk(PAGE_SIZE);
|
||||
if (ptr == (void *)-1) {
|
||||
err(1, "After %u pages: sbrk", totalpages);
|
||||
}
|
||||
totalpages++;
|
||||
lastpage = ptr;
|
||||
if (firstpage == NULL) {
|
||||
firstpage = ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
touchpage(unsigned pagenum)
|
||||
{
|
||||
int *ptr;
|
||||
static void touchpage(unsigned pagenum) {
|
||||
int *ptr;
|
||||
|
||||
ptr = (void *)((uintptr_t)firstpage + PAGE_SIZE * pagenum);
|
||||
*ptr = pagenum;
|
||||
ptr = (void *)((uintptr_t)firstpage + PAGE_SIZE * pagenum);
|
||||
*ptr = pagenum;
|
||||
}
|
||||
|
||||
static
|
||||
unsigned
|
||||
pickpage(unsigned numpages)
|
||||
{
|
||||
unsigned mnum, moffset;
|
||||
unsigned span, val, i;
|
||||
static unsigned pickpage(unsigned numpages) {
|
||||
unsigned mnum, moffset;
|
||||
unsigned span, val, i;
|
||||
|
||||
/* take 1 in 1000 pages uniformly from the entire space */
|
||||
if (random() % 1000 == 0) {
|
||||
return random() % numpages;
|
||||
}
|
||||
/* take 1 in 1000 pages uniformly from the entire space */
|
||||
if (random() % 1000 == 0) {
|
||||
return random() % numpages;
|
||||
}
|
||||
|
||||
/* the rest is taken from the middle 1% */
|
||||
/* the rest is taken from the middle 1% */
|
||||
|
||||
mnum = numpages / 100;
|
||||
if (mnum < touchpages * 2) {
|
||||
mnum = touchpages * 2;
|
||||
}
|
||||
if (mnum >= numpages) {
|
||||
mnum = numpages;
|
||||
}
|
||||
moffset = numpages / 2 - mnum / 2;
|
||||
mnum = numpages / 100;
|
||||
if (mnum < touchpages * 2) {
|
||||
mnum = touchpages * 2;
|
||||
}
|
||||
if (mnum >= numpages) {
|
||||
mnum = numpages;
|
||||
}
|
||||
moffset = numpages / 2 - mnum / 2;
|
||||
|
||||
assert(bias >= 1);
|
||||
span = (mnum + bias - 1) / bias;
|
||||
assert(bias >= 1);
|
||||
span = (mnum + bias - 1) / bias;
|
||||
|
||||
do {
|
||||
val = 0;
|
||||
for (i=0; i<bias; i++) {
|
||||
val += random() % span;
|
||||
}
|
||||
} while (val >= mnum);
|
||||
return moffset + val;
|
||||
do {
|
||||
val = 0;
|
||||
for (i = 0; i < bias; i++) {
|
||||
val += random() % span;
|
||||
}
|
||||
} while (val >= mnum);
|
||||
return moffset + val;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
touchmem(void)
|
||||
{
|
||||
unsigned i, num;
|
||||
static void touchmem(void) {
|
||||
unsigned i, num;
|
||||
|
||||
num = (((uintptr_t)lastpage - (uintptr_t)firstpage) / PAGE_SIZE) + 1;
|
||||
num = (((uintptr_t)lastpage - (uintptr_t)firstpage) / PAGE_SIZE) + 1;
|
||||
|
||||
if (num % 256 == 0) {
|
||||
warnx("%u pages", num);
|
||||
}
|
||||
if (num % 256 == 0) {
|
||||
warnx("%u pages", num);
|
||||
}
|
||||
|
||||
for (i=0; i<touchpages; i++) {
|
||||
touchpage(pickpage(num));
|
||||
}
|
||||
for (i = 0; i < touchpages; i++) {
|
||||
touchpage(pickpage(num));
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
run(void)
|
||||
{
|
||||
while (1) {
|
||||
moremem();
|
||||
touchmem();
|
||||
}
|
||||
static void run(void) {
|
||||
while (1) {
|
||||
moremem();
|
||||
touchmem();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
printsettings(void)
|
||||
{
|
||||
printf("Page size: %u\n", PAGE_SIZE);
|
||||
printf("Allocating %u pages and touching %u pages on each cycle.\n",
|
||||
allocs, touchpages);
|
||||
printf("Page selection bias: %u\n", bias);
|
||||
printf("\n");
|
||||
static void printsettings(void) {
|
||||
printf("Page size: %u\n", PAGE_SIZE);
|
||||
printf("Allocating %u pages and touching %u pages on each cycle.\n", allocs,
|
||||
touchpages);
|
||||
printf("Page selection bias: %u\n", bias);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
warnx("bloat [-a allocs] [-b bias] [-p pages]");
|
||||
warnx(" allocs: number of pages allocated per cycle (default 4)");
|
||||
warnx(" bias: number of dice rolled to touch pages (default 8)");
|
||||
warnx(" pages: pages touched per cycle (default 8)");
|
||||
exit(1);
|
||||
static void usage(void) {
|
||||
warnx("bloat [-a allocs] [-b bias] [-p pages]");
|
||||
warnx(" allocs: number of pages allocated per cycle (default 4)");
|
||||
warnx(" bias: number of dice rolled to touch pages (default 8)");
|
||||
warnx(" pages: pages touched per cycle (default 8)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
/* default mode */
|
||||
allocs = 4;
|
||||
touchpages = 8;
|
||||
bias = 8;
|
||||
/* default mode */
|
||||
allocs = 4;
|
||||
touchpages = 8;
|
||||
bias = 8;
|
||||
|
||||
srandom(1234);
|
||||
srandom(1234);
|
||||
|
||||
for (i=1; i<argc; i++) {
|
||||
if (!strcmp(argv[i], "-a")) {
|
||||
i++;
|
||||
if (i == argc) {
|
||||
errx(1, "-a: option requires argument");
|
||||
}
|
||||
allocs = atoi(argv[i]);
|
||||
if (allocs == 0) {
|
||||
errx(1, "-a: must not be zero");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[i], "-b")) {
|
||||
i++;
|
||||
if (i == argc) {
|
||||
errx(1, "-b: option requires argument");
|
||||
}
|
||||
bias = atoi(argv[i]);
|
||||
if (bias == 0) {
|
||||
errx(1, "-b: must not be zero");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[i], "-h")) {
|
||||
usage();
|
||||
}
|
||||
else if (!strcmp(argv[i], "-p")) {
|
||||
i++;
|
||||
if (i == argc) {
|
||||
errx(1, "-p: option requires argument");
|
||||
}
|
||||
touchpages = atoi(argv[i]);
|
||||
}
|
||||
else {
|
||||
errx(1, "Argument %s not recognized", argv[i]);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-a")) {
|
||||
i++;
|
||||
if (i == argc) {
|
||||
errx(1, "-a: option requires argument");
|
||||
}
|
||||
allocs = atoi(argv[i]);
|
||||
if (allocs == 0) {
|
||||
errx(1, "-a: must not be zero");
|
||||
}
|
||||
} else if (!strcmp(argv[i], "-b")) {
|
||||
i++;
|
||||
if (i == argc) {
|
||||
errx(1, "-b: option requires argument");
|
||||
}
|
||||
bias = atoi(argv[i]);
|
||||
if (bias == 0) {
|
||||
errx(1, "-b: must not be zero");
|
||||
}
|
||||
} else if (!strcmp(argv[i], "-h")) {
|
||||
usage();
|
||||
} else if (!strcmp(argv[i], "-p")) {
|
||||
i++;
|
||||
if (i == argc) {
|
||||
errx(1, "-p: option requires argument");
|
||||
}
|
||||
touchpages = atoi(argv[i]);
|
||||
} else {
|
||||
errx(1, "Argument %s not recognized", argv[i]);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
printsettings();
|
||||
run();
|
||||
return 0;
|
||||
printsettings();
|
||||
run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,22 +37,20 @@
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
char ch=0;
|
||||
int len;
|
||||
int main(void) {
|
||||
char ch = 0;
|
||||
int len;
|
||||
|
||||
while (ch!='q') {
|
||||
len = read(STDIN_FILENO, &ch, 1);
|
||||
if (len < 0) {
|
||||
err(1, "stdin: read");
|
||||
}
|
||||
if (len==0) {
|
||||
/* EOF */
|
||||
break;
|
||||
}
|
||||
write(STDOUT_FILENO, &ch, 1);
|
||||
}
|
||||
return 0;
|
||||
while (ch != 'q') {
|
||||
len = read(STDIN_FILENO, &ch, 1);
|
||||
if (len < 0) {
|
||||
err(1, "stdin: read");
|
||||
}
|
||||
if (len == 0) {
|
||||
/* EOF */
|
||||
break;
|
||||
}
|
||||
write(STDOUT_FILENO, &ch, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -48,341 +48,276 @@
|
||||
#include <err.h>
|
||||
|
||||
#if defined(__mips__)
|
||||
#define KERNEL_ADDR 0x80000000
|
||||
#define INVAL_ADDR 0x40000000
|
||||
#define INSN_TYPE uint32_t
|
||||
#define INVAL_INSN 0x0000003f
|
||||
#define KERNEL_ADDR 0x80000000
|
||||
#define INVAL_ADDR 0x40000000
|
||||
#define INSN_TYPE uint32_t
|
||||
#define INVAL_INSN 0x0000003f
|
||||
#else
|
||||
#error "Please fix this"
|
||||
#endif
|
||||
|
||||
#define MAGIC 123456
|
||||
#define MAGIC 123456
|
||||
|
||||
typedef void (*func)(void);
|
||||
|
||||
static int forking = 1;
|
||||
|
||||
static
|
||||
void
|
||||
read_from_null(void)
|
||||
{
|
||||
int *null = NULL;
|
||||
volatile int x;
|
||||
static void read_from_null(void) {
|
||||
int *null = NULL;
|
||||
volatile int x;
|
||||
|
||||
x = *null;
|
||||
x = *null;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)x;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)x;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
read_from_inval(void)
|
||||
{
|
||||
int *ptr = (int *) INVAL_ADDR;
|
||||
volatile int x;
|
||||
static void read_from_inval(void) {
|
||||
int *ptr = (int *)INVAL_ADDR;
|
||||
volatile int x;
|
||||
|
||||
x = *ptr;
|
||||
x = *ptr;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)x;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)x;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
read_from_kernel(void)
|
||||
{
|
||||
int *ptr = (int *) KERNEL_ADDR;
|
||||
volatile int x;
|
||||
static void read_from_kernel(void) {
|
||||
int *ptr = (int *)KERNEL_ADDR;
|
||||
volatile int x;
|
||||
|
||||
x = *ptr;
|
||||
x = *ptr;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)x;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)x;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
write_to_null(void)
|
||||
{
|
||||
int *null = NULL;
|
||||
*null = 6;
|
||||
static void write_to_null(void) {
|
||||
int *null = NULL;
|
||||
*null = 6;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
write_to_inval(void)
|
||||
{
|
||||
int *ptr = (int *) INVAL_ADDR;
|
||||
*ptr = 8;
|
||||
static void write_to_inval(void) {
|
||||
int *ptr = (int *)INVAL_ADDR;
|
||||
*ptr = 8;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
write_to_code(void)
|
||||
{
|
||||
INSN_TYPE *x = (INSN_TYPE *)write_to_code;
|
||||
*x = INVAL_INSN;
|
||||
static void write_to_code(void) {
|
||||
INSN_TYPE *x = (INSN_TYPE *)write_to_code;
|
||||
*x = INVAL_INSN;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
write_to_kernel(void)
|
||||
{
|
||||
int *ptr = (int *) KERNEL_ADDR;
|
||||
*ptr = 8;
|
||||
static void write_to_kernel(void) {
|
||||
int *ptr = (int *)KERNEL_ADDR;
|
||||
*ptr = 8;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
jump_to_null(void)
|
||||
{
|
||||
func f = NULL;
|
||||
f();
|
||||
static void jump_to_null(void) {
|
||||
func f = NULL;
|
||||
f();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
jump_to_inval(void)
|
||||
{
|
||||
func f = (func) INVAL_ADDR;
|
||||
f();
|
||||
static void jump_to_inval(void) {
|
||||
func f = (func)INVAL_ADDR;
|
||||
f();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
jump_to_kernel(void)
|
||||
{
|
||||
func f = (func) KERNEL_ADDR;
|
||||
f();
|
||||
static void jump_to_kernel(void) {
|
||||
func f = (func)KERNEL_ADDR;
|
||||
f();
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
illegal_instruction(void)
|
||||
{
|
||||
static void illegal_instruction(void) {
|
||||
#if defined(__mips__)
|
||||
asm(".long 0x0000003f");
|
||||
asm(".long 0x0000003f");
|
||||
#else
|
||||
#error "Please fix this"
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
alignment_error(void)
|
||||
{
|
||||
int x;
|
||||
int *ptr, *badptr;
|
||||
volatile uintptr_t ptrval;
|
||||
volatile int j;
|
||||
static void alignment_error(void) {
|
||||
int x;
|
||||
int *ptr, *badptr;
|
||||
volatile uintptr_t ptrval;
|
||||
volatile int j;
|
||||
|
||||
x = 0;
|
||||
ptr = &x;
|
||||
/*
|
||||
* Try to hide what's going on from gcc; gcc 4.8 seems to
|
||||
* detect the unaligned access and issue unaligned read
|
||||
* instructions for it, so then it doesn't fault. Feh.
|
||||
*/
|
||||
ptrval = (uintptr_t)ptr;
|
||||
ptrval++;
|
||||
badptr = (int *)ptrval;
|
||||
x = 0;
|
||||
ptr = &x;
|
||||
/*
|
||||
* Try to hide what's going on from gcc; gcc 4.8 seems to
|
||||
* detect the unaligned access and issue unaligned read
|
||||
* instructions for it, so then it doesn't fault. Feh.
|
||||
*/
|
||||
ptrval = (uintptr_t)ptr;
|
||||
ptrval++;
|
||||
badptr = (int *)ptrval;
|
||||
|
||||
j = *badptr;
|
||||
j = *badptr;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)j;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)j;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
divide_by_zero(void)
|
||||
{
|
||||
volatile int x = 6;
|
||||
volatile int z = 0;
|
||||
volatile int a;
|
||||
static void divide_by_zero(void) {
|
||||
volatile int x = 6;
|
||||
volatile int z = 0;
|
||||
volatile int a;
|
||||
|
||||
a = x/z;
|
||||
a = x / z;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)a;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)a;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mod_by_zero(void)
|
||||
{
|
||||
volatile int x = 6;
|
||||
volatile int z = 0;
|
||||
volatile int a;
|
||||
static void mod_by_zero(void) {
|
||||
volatile int x = 6;
|
||||
volatile int z = 0;
|
||||
volatile int a;
|
||||
|
||||
a = x%z;
|
||||
a = x % z;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)a;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)a;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
recurse_inf(void)
|
||||
{
|
||||
volatile char buf[16];
|
||||
static void recurse_inf(void) {
|
||||
volatile char buf[16];
|
||||
|
||||
buf[0] = 0;
|
||||
recurse_inf();
|
||||
buf[0] = 1;
|
||||
buf[0] = 0;
|
||||
recurse_inf();
|
||||
buf[0] = 1;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)buf;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)buf;
|
||||
}
|
||||
|
||||
static struct {
|
||||
int ch;
|
||||
const char *name;
|
||||
func f;
|
||||
int sig;
|
||||
} ops[] = {{'a', "read from NULL", read_from_null, SIGSEGV},
|
||||
{'b', "read from invalid address", read_from_inval, SIGSEGV},
|
||||
{'c', "read from kernel address", read_from_kernel, SIGBUS},
|
||||
{'d', "write to NULL", write_to_null, SIGSEGV},
|
||||
{'e', "write to invalid address", write_to_inval, SIGSEGV},
|
||||
{'f', "write to code segment", write_to_code, SIGSEGV},
|
||||
{'g', "write to kernel address", write_to_kernel, SIGBUS},
|
||||
{'h', "jump to NULL", jump_to_null, SIGSEGV},
|
||||
{'i', "jump to invalid address", jump_to_inval, SIGSEGV},
|
||||
{'j', "jump to kernel address", jump_to_kernel, SIGBUS},
|
||||
{'k', "alignment error", alignment_error, SIGBUS},
|
||||
{'l', "illegal instruction", illegal_instruction, SIGILL},
|
||||
{'m', "divide by zero", divide_by_zero, SIGTRAP},
|
||||
{'n', "mod by zero", mod_by_zero, SIGTRAP},
|
||||
{'o', "Recurse infinitely", recurse_inf, SIGSEGV},
|
||||
{0, NULL, NULL, 0}};
|
||||
|
||||
static
|
||||
struct {
|
||||
int ch;
|
||||
const char *name;
|
||||
func f;
|
||||
int sig;
|
||||
} ops[] = {
|
||||
{ 'a', "read from NULL", read_from_null, SIGSEGV },
|
||||
{ 'b', "read from invalid address", read_from_inval, SIGSEGV },
|
||||
{ 'c', "read from kernel address", read_from_kernel, SIGBUS },
|
||||
{ 'd', "write to NULL", write_to_null, SIGSEGV },
|
||||
{ 'e', "write to invalid address", write_to_inval, SIGSEGV },
|
||||
{ 'f', "write to code segment", write_to_code, SIGSEGV },
|
||||
{ 'g', "write to kernel address", write_to_kernel, SIGBUS },
|
||||
{ 'h', "jump to NULL", jump_to_null, SIGSEGV },
|
||||
{ 'i', "jump to invalid address", jump_to_inval, SIGSEGV },
|
||||
{ 'j', "jump to kernel address", jump_to_kernel, SIGBUS },
|
||||
{ 'k', "alignment error", alignment_error, SIGBUS },
|
||||
{ 'l', "illegal instruction", illegal_instruction, SIGILL },
|
||||
{ 'm', "divide by zero", divide_by_zero, SIGTRAP },
|
||||
{ 'n', "mod by zero", mod_by_zero, SIGTRAP },
|
||||
{ 'o', "Recurse infinitely", recurse_inf, SIGSEGV },
|
||||
{ 0, NULL, NULL, 0 }
|
||||
};
|
||||
static void runop(int op) {
|
||||
int opindex;
|
||||
pid_t pid;
|
||||
int status;
|
||||
int ok;
|
||||
|
||||
static
|
||||
void
|
||||
runop(int op)
|
||||
{
|
||||
int opindex;
|
||||
pid_t pid;
|
||||
int status;
|
||||
int ok;
|
||||
if (op == '*') {
|
||||
for (unsigned i = 0; ops[i].name; i++) {
|
||||
runop(ops[i].ch);
|
||||
}
|
||||
return;
|
||||
} else if (op == '-') {
|
||||
forking = 0;
|
||||
warnx("Forking disabled - next try will be the last");
|
||||
return;
|
||||
} else if (op == '+') {
|
||||
forking = 1;
|
||||
warnx("Forking enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (op=='*') {
|
||||
for (unsigned i=0; ops[i].name; i++) {
|
||||
runop(ops[i].ch);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (op == '-') {
|
||||
forking = 0;
|
||||
warnx("Forking disabled - next try will be the last");
|
||||
return;
|
||||
}
|
||||
else if (op == '+') {
|
||||
forking = 1;
|
||||
warnx("Forking enabled.");
|
||||
return;
|
||||
}
|
||||
/* intentionally don't check if op is in bounds :) */
|
||||
opindex = op - 'a';
|
||||
|
||||
/* intentionally don't check if op is in bounds :) */
|
||||
opindex = op-'a';
|
||||
printf("Running: [%c] %s\n", ops[opindex].ch, ops[opindex].name);
|
||||
|
||||
printf("Running: [%c] %s\n", ops[opindex].ch, ops[opindex].name);
|
||||
if (forking) {
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
/* error */
|
||||
err(1, "fork");
|
||||
} else if (pid > 0) {
|
||||
/* parent */
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
ok = 0;
|
||||
if (WIFSIGNALED(status)) {
|
||||
printf("Signal %d\n", WTERMSIG(status));
|
||||
if (WTERMSIG(status) == ops[opindex].sig) {
|
||||
ok = 1;
|
||||
}
|
||||
} else {
|
||||
printf("Exit %d\n", WEXITSTATUS(status));
|
||||
if (WEXITSTATUS(status) == MAGIC) {
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
printf("Ok.\n");
|
||||
} else {
|
||||
printf("FAILED: expected signal %d\n", ops[opindex].sig);
|
||||
}
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* child, or not forking */
|
||||
|
||||
if (forking) {
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
/* error */
|
||||
err(1, "fork");
|
||||
}
|
||||
else if (pid > 0) {
|
||||
/* parent */
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
ok = 0;
|
||||
if (WIFSIGNALED(status)) {
|
||||
printf("Signal %d\n", WTERMSIG(status));
|
||||
if (WTERMSIG(status) == ops[opindex].sig) {
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Exit %d\n", WEXITSTATUS(status));
|
||||
if (WEXITSTATUS(status) == MAGIC) {
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
printf("Ok.\n");
|
||||
}
|
||||
else {
|
||||
printf("FAILED: expected signal %d\n",
|
||||
ops[opindex].sig);
|
||||
}
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* child, or not forking */
|
||||
ops[opindex].f();
|
||||
|
||||
ops[opindex].f();
|
||||
|
||||
if (op == 'f') {
|
||||
warnx(".... I guess you don't support read-only segments");
|
||||
/* use this magic signaling value so parent doesn't say FAIL */
|
||||
_exit(MAGIC);
|
||||
}
|
||||
errx(1, "I wasn't killed!");
|
||||
if (op == 'f') {
|
||||
warnx(".... I guess you don't support read-only segments");
|
||||
/* use this magic signaling value so parent doesn't say FAIL */
|
||||
_exit(MAGIC);
|
||||
}
|
||||
errx(1, "I wasn't killed!");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ask(void)
|
||||
{
|
||||
unsigned i;
|
||||
int op;
|
||||
static void ask(void) {
|
||||
unsigned i;
|
||||
int op;
|
||||
|
||||
while (1) {
|
||||
while (1) {
|
||||
|
||||
for (i=0; ops[i].name; i++) {
|
||||
printf("[%c] %s\n", ops[i].ch, ops[i].name);
|
||||
}
|
||||
printf("[-] Disable forking\n");
|
||||
printf("[+] Enable forking (default)\n");
|
||||
printf("[*] Run everything\n");
|
||||
printf("[!] Quit\n");
|
||||
for (i = 0; ops[i].name; i++) {
|
||||
printf("[%c] %s\n", ops[i].ch, ops[i].name);
|
||||
}
|
||||
printf("[-] Disable forking\n");
|
||||
printf("[+] Enable forking (default)\n");
|
||||
printf("[*] Run everything\n");
|
||||
printf("[!] Quit\n");
|
||||
|
||||
printf("Choose: ");
|
||||
op = getchar();
|
||||
printf("Choose: ");
|
||||
op = getchar();
|
||||
|
||||
if (op == '!') {
|
||||
break;
|
||||
}
|
||||
if (op == '!') {
|
||||
break;
|
||||
}
|
||||
|
||||
runop(op);
|
||||
}
|
||||
runop(op);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc == 0 || argc == 1) {
|
||||
/* no arguments */
|
||||
ask();
|
||||
}
|
||||
else {
|
||||
/* run the selected ops */
|
||||
for (int i=1; i<argc; i++) {
|
||||
for (size_t j=0; argv[i][j]; j++) {
|
||||
runop(argv[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 0 || argc == 1) {
|
||||
/* no arguments */
|
||||
ask();
|
||||
} else {
|
||||
/* run the selected ops */
|
||||
for (int i = 1; i < argc; i++) {
|
||||
for (size_t j = 0; argv[i][j]; j++) {
|
||||
runop(argv[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,58 +44,56 @@
|
||||
* DEFAULT is the default stride.
|
||||
* Note that SIZE and DEFAULT should be relatively prime.
|
||||
*/
|
||||
#define SIZE (1024*1024/sizeof(struct entry))
|
||||
#define DEFAULT 477
|
||||
#define SIZE (1024 * 1024 / sizeof(struct entry))
|
||||
#define DEFAULT 477
|
||||
|
||||
struct entry {
|
||||
struct entry *e;
|
||||
struct entry *e;
|
||||
};
|
||||
|
||||
struct entry array[SIZE];
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
volatile struct entry *e;
|
||||
unsigned i, stride;
|
||||
int main(int argc, char **argv) {
|
||||
volatile struct entry *e;
|
||||
unsigned i, stride;
|
||||
|
||||
stride = DEFAULT;
|
||||
if (argc == 2) {
|
||||
stride = atoi(argv[1]);
|
||||
}
|
||||
if (stride <= 0 || argc > 2) {
|
||||
printf("Usage: ctest [stridesize]\n");
|
||||
printf(" stridesize should not be a multiple of 2.\n");
|
||||
return 1;
|
||||
}
|
||||
stride = DEFAULT;
|
||||
if (argc == 2) {
|
||||
stride = atoi(argv[1]);
|
||||
}
|
||||
if (stride <= 0 || argc > 2) {
|
||||
printf("Usage: ctest [stridesize]\n");
|
||||
printf(" stridesize should not be a multiple of 2.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Starting ctest: stride %d\n", stride);
|
||||
printf("Starting ctest: stride %d\n", stride);
|
||||
|
||||
/*
|
||||
* Generate a huge linked list, with each entry pointing to
|
||||
* the slot STRIDE entries above it. As long as STRIDE and SIZE
|
||||
* are relatively prime, this will put all the entries on one
|
||||
* list. Otherwise you will get multiple disjoint lists. (All
|
||||
* these lists will be circular.)
|
||||
*/
|
||||
for (i=0; i<SIZE; i++) {
|
||||
array[i].e = &array[(i+stride) % SIZE];
|
||||
}
|
||||
/*
|
||||
* Generate a huge linked list, with each entry pointing to
|
||||
* the slot STRIDE entries above it. As long as STRIDE and SIZE
|
||||
* are relatively prime, this will put all the entries on one
|
||||
* list. Otherwise you will get multiple disjoint lists. (All
|
||||
* these lists will be circular.)
|
||||
*/
|
||||
for (i = 0; i < SIZE; i++) {
|
||||
array[i].e = &array[(i + stride) % SIZE];
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse the list. We stop after hitting each element once.
|
||||
*
|
||||
* (If STRIDE was even, this will hit some elements more than
|
||||
* once and others not at all.)
|
||||
*/
|
||||
e = &array[0];
|
||||
for (i=0; i<SIZE; i++) {
|
||||
if (i % stride == 0) {
|
||||
putchar('.');
|
||||
}
|
||||
e = e->e;
|
||||
}
|
||||
/*
|
||||
* Traverse the list. We stop after hitting each element once.
|
||||
*
|
||||
* (If STRIDE was even, this will hit some elements more than
|
||||
* once and others not at all.)
|
||||
*/
|
||||
e = &array[0];
|
||||
for (i = 0; i < SIZE; i++) {
|
||||
if (i % stride == 0) {
|
||||
putchar('.');
|
||||
}
|
||||
e = e->e;
|
||||
}
|
||||
|
||||
printf("\nDone!\n");
|
||||
return 0;
|
||||
printf("\nDone!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,40 +44,37 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NTRIES 100 /* loop count */
|
||||
#define NPROCS 5 /* actually totals 4x this +1 processes */
|
||||
#define NTRIES 100 /* loop count */
|
||||
#define NPROCS 5 /* actually totals 4x this +1 processes */
|
||||
|
||||
#define TESTDIR "dirconc"
|
||||
#define NNAMES 4
|
||||
#define NAMESIZE 32
|
||||
#define TESTDIR "dirconc"
|
||||
#define NNAMES 4
|
||||
#define NAMESIZE 32
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static const char *const names[NNAMES] = {
|
||||
"aaaa",
|
||||
"bbbb",
|
||||
"cccc",
|
||||
"dddd",
|
||||
"aaaa",
|
||||
"bbbb",
|
||||
"cccc",
|
||||
"dddd",
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
choose_name(char *buf, size_t len)
|
||||
{
|
||||
const char *a, *b, *c;
|
||||
static void choose_name(char *buf, size_t len) {
|
||||
const char *a, *b, *c;
|
||||
|
||||
a = names[random()%NNAMES];
|
||||
if (random()%2==0) {
|
||||
snprintf(buf, len, "%s", a);
|
||||
return;
|
||||
}
|
||||
b = names[random()%NNAMES];
|
||||
if (random()%2==0) {
|
||||
snprintf(buf, len, "%s/%s", a, b);
|
||||
return;
|
||||
}
|
||||
c = names[random()%NNAMES];
|
||||
snprintf(buf, len, "%s/%s/%s", a, b, c);
|
||||
a = names[random() % NNAMES];
|
||||
if (random() % 2 == 0) {
|
||||
snprintf(buf, len, "%s", a);
|
||||
return;
|
||||
}
|
||||
b = names[random() % NNAMES];
|
||||
if (random() % 2 == 0) {
|
||||
snprintf(buf, len, "%s/%s", a, b);
|
||||
return;
|
||||
}
|
||||
c = names[random() % NNAMES];
|
||||
snprintf(buf, len, "%s/%s/%s", a, b, c);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -86,277 +83,224 @@ choose_name(char *buf, size_t len)
|
||||
* The purpose of this is to be atomic. In our world, straight
|
||||
* printf tends not to be.
|
||||
*/
|
||||
static
|
||||
void
|
||||
static void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__format__(__printf__, 1, 2)))
|
||||
__attribute__((__format__(__printf__, 1, 2)))
|
||||
#endif
|
||||
say(const char *fmt, ...)
|
||||
{
|
||||
char buf[512];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
write(STDOUT_FILENO, buf, strlen(buf));
|
||||
say(const char *fmt, ...) {
|
||||
char buf[512];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
write(STDOUT_FILENO, buf, strlen(buf));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
dorename(const char *name1, const char *name2)
|
||||
{
|
||||
if (rename(name1, name2) < 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTEMPTY:
|
||||
case EINVAL:
|
||||
break;
|
||||
default:
|
||||
say("pid %d: rename %s -> %s: %s\n",
|
||||
getpid(), name1, name2, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void dorename(const char *name1, const char *name2) {
|
||||
if (rename(name1, name2) < 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTEMPTY:
|
||||
case EINVAL:
|
||||
break;
|
||||
default:
|
||||
say("pid %d: rename %s -> %s: %s\n", getpid(), name1, name2,
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
domkdir(const char *name)
|
||||
{
|
||||
if (mkdir(name, 0775)<0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case EEXIST:
|
||||
break;
|
||||
default:
|
||||
say("pid %d: mkdir %s: %s\n",
|
||||
getpid(), name, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void domkdir(const char *name) {
|
||||
if (mkdir(name, 0775) < 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case EEXIST:
|
||||
break;
|
||||
default:
|
||||
say("pid %d: mkdir %s: %s\n", getpid(), name, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dormdir(const char *name)
|
||||
{
|
||||
if (rmdir(name)<0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTEMPTY:
|
||||
break;
|
||||
default:
|
||||
say("pid %d: rmdir %s: %s\n",
|
||||
getpid(), name, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void dormdir(const char *name) {
|
||||
if (rmdir(name) < 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTEMPTY:
|
||||
break;
|
||||
default:
|
||||
say("pid %d: rmdir %s: %s\n", getpid(), name, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
cleanup_rmdir(const char *name)
|
||||
{
|
||||
if (rmdir(name)<0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
say("cleanup (pid %d): rmdir %s: %s\n",
|
||||
getpid(), name, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void cleanup_rmdir(const char *name) {
|
||||
if (rmdir(name) < 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
say("cleanup (pid %d): rmdir %s: %s\n", getpid(), name, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
rename_proc(void)
|
||||
{
|
||||
char name1[NAMESIZE], name2[NAMESIZE];
|
||||
int ct;
|
||||
static void rename_proc(void) {
|
||||
char name1[NAMESIZE], name2[NAMESIZE];
|
||||
int ct;
|
||||
|
||||
for (ct=0; ct<NTRIES; ct++) {
|
||||
choose_name(name1, sizeof(name1));
|
||||
choose_name(name2, sizeof(name2));
|
||||
say("pid %2d: rename %s -> %s\n", (int)getpid(), name1, name2);
|
||||
dorename(name1, name2);
|
||||
}
|
||||
for (ct = 0; ct < NTRIES; ct++) {
|
||||
choose_name(name1, sizeof(name1));
|
||||
choose_name(name2, sizeof(name2));
|
||||
say("pid %2d: rename %s -> %s\n", (int)getpid(), name1, name2);
|
||||
dorename(name1, name2);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mkdir_proc(void)
|
||||
{
|
||||
char name[NAMESIZE];
|
||||
int ct;
|
||||
static void mkdir_proc(void) {
|
||||
char name[NAMESIZE];
|
||||
int ct;
|
||||
|
||||
for (ct=0; ct<NTRIES; ct++) {
|
||||
choose_name(name, sizeof(name));
|
||||
say("pid %2d: mkdir %s\n", (int)getpid(), name);
|
||||
domkdir(name);
|
||||
}
|
||||
for (ct = 0; ct < NTRIES; ct++) {
|
||||
choose_name(name, sizeof(name));
|
||||
say("pid %2d: mkdir %s\n", (int)getpid(), name);
|
||||
domkdir(name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_proc(void)
|
||||
{
|
||||
char name[NAMESIZE];
|
||||
int ct;
|
||||
static void rmdir_proc(void) {
|
||||
char name[NAMESIZE];
|
||||
int ct;
|
||||
|
||||
for (ct=0; ct<NTRIES; ct++) {
|
||||
choose_name(name, sizeof(name));
|
||||
say("pid %2d: rmdir %s\n", (int)getpid(), name);
|
||||
dormdir(name);
|
||||
}
|
||||
for (ct = 0; ct < NTRIES; ct++) {
|
||||
choose_name(name, sizeof(name));
|
||||
say("pid %2d: rmdir %s\n", (int)getpid(), name);
|
||||
dormdir(name);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
pid_t
|
||||
dofork(void (*func)(void))
|
||||
{
|
||||
pid_t pid;
|
||||
static pid_t dofork(void (*func)(void)) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
say("fork: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
func();
|
||||
exit(0);
|
||||
}
|
||||
return pid;
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
say("fork: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
func();
|
||||
exit(0);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
run(void)
|
||||
{
|
||||
pid_t pids[NPROCS*4], wp;
|
||||
int i, status;
|
||||
static void run(void) {
|
||||
pid_t pids[NPROCS * 4], wp;
|
||||
int i, status;
|
||||
|
||||
for (i=0; i<NPROCS; i++) {
|
||||
pids[i*4] = dofork(mkdir_proc);
|
||||
pids[i*4+1] = dofork(mkdir_proc);
|
||||
pids[i*4+2] = dofork(rename_proc);
|
||||
pids[i*4+3] = dofork(rmdir_proc);
|
||||
}
|
||||
for (i = 0; i < NPROCS; i++) {
|
||||
pids[i * 4] = dofork(mkdir_proc);
|
||||
pids[i * 4 + 1] = dofork(mkdir_proc);
|
||||
pids[i * 4 + 2] = dofork(rename_proc);
|
||||
pids[i * 4 + 3] = dofork(rmdir_proc);
|
||||
}
|
||||
|
||||
for (i=0; i<NPROCS*4; i++) {
|
||||
if (pids[i]>=0) {
|
||||
wp = waitpid(pids[i], &status, 0);
|
||||
if (wp<0) {
|
||||
say("waitpid %d: %s\n", (int) pids[i],
|
||||
strerror(errno));
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
say("pid %d: signal %d\n", (int) pids[i],
|
||||
WTERMSIG(status));
|
||||
}
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
|
||||
say("pid %d: exit %d\n", (int) pids[i],
|
||||
WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NPROCS * 4; i++) {
|
||||
if (pids[i] >= 0) {
|
||||
wp = waitpid(pids[i], &status, 0);
|
||||
if (wp < 0) {
|
||||
say("waitpid %d: %s\n", (int)pids[i], strerror(errno));
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
say("pid %d: signal %d\n", (int)pids[i], WTERMSIG(status));
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
say("pid %d: exit %d\n", (int)pids[i], WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
setup(const char *fs)
|
||||
{
|
||||
if (chdir(fs)<0) {
|
||||
say("chdir: %s: %s\n", fs, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (mkdir(TESTDIR, 0775)<0) {
|
||||
say("mkdir: %s: %s\n", TESTDIR, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (chdir(TESTDIR)<0) {
|
||||
say("chdir: %s: %s\n", TESTDIR, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
static void setup(const char *fs) {
|
||||
if (chdir(fs) < 0) {
|
||||
say("chdir: %s: %s\n", fs, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (mkdir(TESTDIR, 0775) < 0) {
|
||||
say("mkdir: %s: %s\n", TESTDIR, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (chdir(TESTDIR) < 0) {
|
||||
say("chdir: %s: %s\n", TESTDIR, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
recursive_cleanup(const char *sofar, int depth)
|
||||
{
|
||||
char buf[NAMESIZE*32];
|
||||
int i;
|
||||
static void recursive_cleanup(const char *sofar, int depth) {
|
||||
char buf[NAMESIZE * 32];
|
||||
int i;
|
||||
|
||||
for (i=0; i<NNAMES; i++) {
|
||||
snprintf(buf, sizeof(buf), "%s/%s", sofar, names[i]);
|
||||
if (rmdir(buf)<0) {
|
||||
if (errno==ENOTEMPTY) {
|
||||
recursive_cleanup(buf, depth+1);
|
||||
cleanup_rmdir(buf);
|
||||
}
|
||||
else if (errno!=ENOENT) {
|
||||
say("cleanup (pid %d): rmdir %s: %s\n",
|
||||
getpid(), buf, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NNAMES; i++) {
|
||||
snprintf(buf, sizeof(buf), "%s/%s", sofar, names[i]);
|
||||
if (rmdir(buf) < 0) {
|
||||
if (errno == ENOTEMPTY) {
|
||||
recursive_cleanup(buf, depth + 1);
|
||||
cleanup_rmdir(buf);
|
||||
} else if (errno != ENOENT) {
|
||||
say("cleanup (pid %d): rmdir %s: %s\n", getpid(), buf, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
recursive_cleanup(".", 0);
|
||||
static void cleanup(void) {
|
||||
recursive_cleanup(".", 0);
|
||||
|
||||
chdir("..");
|
||||
cleanup_rmdir(TESTDIR);
|
||||
chdir("..");
|
||||
cleanup_rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *fs;
|
||||
long seed = 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *fs;
|
||||
long seed = 0;
|
||||
|
||||
say("Concurrent directory ops test\n");
|
||||
say("Concurrent directory ops test\n");
|
||||
|
||||
if (argc==0 || argv==NULL) {
|
||||
say("Warning: argc is 0 - assuming you mean to run on lhd1: "
|
||||
"with seed 0\n");
|
||||
fs = "lhd1:";
|
||||
}
|
||||
else if (argc==2) {
|
||||
fs = argv[1];
|
||||
}
|
||||
else if (argc==3) {
|
||||
fs = argv[1];
|
||||
seed = atoi(argv[2]);
|
||||
}
|
||||
else {
|
||||
say("Usage: dirconc filesystem [random-seed]\n");
|
||||
exit(1);
|
||||
}
|
||||
if (argc == 0 || argv == NULL) {
|
||||
say("Warning: argc is 0 - assuming you mean to run on lhd1: "
|
||||
"with seed 0\n");
|
||||
fs = "lhd1:";
|
||||
} else if (argc == 2) {
|
||||
fs = argv[1];
|
||||
} else if (argc == 3) {
|
||||
fs = argv[1];
|
||||
seed = atoi(argv[2]);
|
||||
} else {
|
||||
say("Usage: dirconc filesystem [random-seed]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
srandom(seed);
|
||||
setup(fs);
|
||||
say("Starting in %s/%s\n", fs, TESTDIR);
|
||||
srandom(seed);
|
||||
setup(fs);
|
||||
say("Starting in %s/%s\n", fs, TESTDIR);
|
||||
|
||||
run();
|
||||
run();
|
||||
|
||||
say("Cleaning up\n");
|
||||
cleanup();
|
||||
say("Cleaning up\n");
|
||||
cleanup();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -57,32 +57,17 @@
|
||||
#define TESTDIR "seektestdir"
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
int make_it;
|
||||
off_t pos;
|
||||
const char *name;
|
||||
int make_it;
|
||||
off_t pos;
|
||||
} testfiles[] = {
|
||||
{ ".", 0, -1 },
|
||||
{ "..", 0, -1 },
|
||||
{ "ridcully", 1, -1 },
|
||||
{ "weatherwax", 1, -1 },
|
||||
{ "ogg", 1, -1 },
|
||||
{ "vorbis", 1, -1 },
|
||||
{ "verence", 1, -1 },
|
||||
{ "magrat", 1, -1 },
|
||||
{ "agnes", 1, -1 },
|
||||
{ "rincewind", 1, -1 },
|
||||
{ "angua", 1, -1 },
|
||||
{ "cherry", 1, -1 },
|
||||
{ "dorfl", 1, -1 },
|
||||
{ "nobby", 1, -1 },
|
||||
{ "carrot", 1, -1 },
|
||||
{ "vimes", 1, -1 },
|
||||
{ "detritus", 1, -1 },
|
||||
{ "twoflower", 1, -1 },
|
||||
{ "teatime", 1, -1 },
|
||||
{ "qu", 1, -1 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
{".", 0, -1}, {"..", 0, -1}, {"ridcully", 1, -1},
|
||||
{"weatherwax", 1, -1}, {"ogg", 1, -1}, {"vorbis", 1, -1},
|
||||
{"verence", 1, -1}, {"magrat", 1, -1}, {"agnes", 1, -1},
|
||||
{"rincewind", 1, -1}, {"angua", 1, -1}, {"cherry", 1, -1},
|
||||
{"dorfl", 1, -1}, {"nobby", 1, -1}, {"carrot", 1, -1},
|
||||
{"vimes", 1, -1}, {"detritus", 1, -1}, {"twoflower", 1, -1},
|
||||
{"teatime", 1, -1}, {"qu", 1, -1}, {NULL, 0, 0}};
|
||||
|
||||
/************************************************************/
|
||||
/* Test code */
|
||||
@@ -90,466 +75,412 @@ static struct {
|
||||
|
||||
static int dirfd;
|
||||
|
||||
static
|
||||
int
|
||||
findentry(const char *name)
|
||||
{
|
||||
int i;
|
||||
static int findentry(const char *name) {
|
||||
int i;
|
||||
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
if (!strcmp(testfiles[i].name, name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
if (!strcmp(testfiles[i].name, name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
openit(void)
|
||||
{
|
||||
dirfd = open(".", O_RDONLY);
|
||||
if (dirfd < 0) {
|
||||
err(1, ".: open");
|
||||
}
|
||||
static void openit(void) {
|
||||
dirfd = open(".", O_RDONLY);
|
||||
if (dirfd < 0) {
|
||||
err(1, ".: open");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
closeit(void)
|
||||
{
|
||||
if (close(dirfd)<0) {
|
||||
err(1, ".: close");
|
||||
}
|
||||
dirfd = -1;
|
||||
static void closeit(void) {
|
||||
if (close(dirfd) < 0) {
|
||||
err(1, ".: close");
|
||||
}
|
||||
dirfd = -1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readit(void)
|
||||
{
|
||||
char buf[4096];
|
||||
off_t pos;
|
||||
int len;
|
||||
int n, i, ix;
|
||||
static void readit(void) {
|
||||
char buf[4096];
|
||||
off_t pos;
|
||||
int len;
|
||||
int n, i, ix;
|
||||
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
testfiles[i].pos = -1;
|
||||
}
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
testfiles[i].pos = -1;
|
||||
}
|
||||
|
||||
pos = lseek(dirfd, 0, SEEK_CUR);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_CUR)");
|
||||
}
|
||||
n = 0;
|
||||
pos = lseek(dirfd, 0, SEEK_CUR);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_CUR)");
|
||||
}
|
||||
n = 0;
|
||||
|
||||
while ((len = getdirentry(dirfd, buf, sizeof(buf)-1)) > 0) {
|
||||
while ((len = getdirentry(dirfd, buf, sizeof(buf) - 1)) > 0) {
|
||||
|
||||
if ((unsigned)len >= sizeof(buf)-1) {
|
||||
errx(1, ".: entry %d: getdirentry returned "
|
||||
"invalid length %d", n, len);
|
||||
}
|
||||
buf[len] = 0;
|
||||
ix = findentry(buf);
|
||||
if (ix < 0) {
|
||||
errx(1, ".: entry %d: getdirentry returned "
|
||||
"unexpected name %s", n, buf);
|
||||
}
|
||||
if ((unsigned)len >= sizeof(buf) - 1) {
|
||||
errx(1,
|
||||
".: entry %d: getdirentry returned "
|
||||
"invalid length %d",
|
||||
n, len);
|
||||
}
|
||||
buf[len] = 0;
|
||||
ix = findentry(buf);
|
||||
if (ix < 0) {
|
||||
errx(1,
|
||||
".: entry %d: getdirentry returned "
|
||||
"unexpected name %s",
|
||||
n, buf);
|
||||
}
|
||||
|
||||
if (testfiles[ix].pos >= 0) {
|
||||
errx(1, ".: entry %d: getdirentry returned "
|
||||
"%s a second time", n, buf);
|
||||
}
|
||||
if (testfiles[ix].pos >= 0) {
|
||||
errx(1,
|
||||
".: entry %d: getdirentry returned "
|
||||
"%s a second time",
|
||||
n, buf);
|
||||
}
|
||||
|
||||
testfiles[ix].pos = pos;
|
||||
testfiles[ix].pos = pos;
|
||||
|
||||
pos = lseek(dirfd, 0, SEEK_CUR);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_CUR)");
|
||||
}
|
||||
n++;
|
||||
}
|
||||
if (len<0) {
|
||||
err(1, ".: entry %d: getdirentry", n);
|
||||
}
|
||||
pos = lseek(dirfd, 0, SEEK_CUR);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_CUR)");
|
||||
}
|
||||
n++;
|
||||
}
|
||||
if (len < 0) {
|
||||
err(1, ".: entry %d: getdirentry", n);
|
||||
}
|
||||
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
if (testfiles[i].pos < 0) {
|
||||
errx(1, ".: getdirentry failed to return %s",
|
||||
testfiles[i].name);
|
||||
}
|
||||
}
|
||||
if (i!=n) {
|
||||
/*
|
||||
* If all of the other checks have passed, this should not
|
||||
* be able to fail. But... just in case I forgot something
|
||||
* or there's a bug...
|
||||
*/
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
if (testfiles[i].pos < 0) {
|
||||
errx(1, ".: getdirentry failed to return %s", testfiles[i].name);
|
||||
}
|
||||
}
|
||||
if (i != n) {
|
||||
/*
|
||||
* If all of the other checks have passed, this should not
|
||||
* be able to fail. But... just in case I forgot something
|
||||
* or there's a bug...
|
||||
*/
|
||||
|
||||
errx(1, ".: getdirentry returned %d names, not %d (huh...?)",
|
||||
n, i);
|
||||
}
|
||||
errx(1, ".: getdirentry returned %d names, not %d (huh...?)", n, i);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
firstread(void)
|
||||
{
|
||||
off_t pos;
|
||||
static void firstread(void) {
|
||||
off_t pos;
|
||||
|
||||
pos = lseek(dirfd, 0, SEEK_CUR);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_CUR)");
|
||||
}
|
||||
if (pos != 0) {
|
||||
errx(1, ".: File position after open not 0");
|
||||
}
|
||||
pos = lseek(dirfd, 0, SEEK_CUR);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_CUR)");
|
||||
}
|
||||
if (pos != 0) {
|
||||
errx(1, ".: File position after open not 0");
|
||||
}
|
||||
|
||||
printf("Scanning directory...\n");
|
||||
printf("Scanning directory...\n");
|
||||
|
||||
readit();
|
||||
readit();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
doreadat0(void)
|
||||
{
|
||||
off_t pos;
|
||||
static void doreadat0(void) {
|
||||
off_t pos;
|
||||
|
||||
printf("Rewinding directory and reading it again...\n");
|
||||
printf("Rewinding directory and reading it again...\n");
|
||||
|
||||
pos = lseek(dirfd, 0, SEEK_SET);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_SET)");
|
||||
}
|
||||
if (pos != 0) {
|
||||
errx(1, ".: lseek(0, SEEK_SET) returned %ld", (long) pos);
|
||||
}
|
||||
pos = lseek(dirfd, 0, SEEK_SET);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_SET)");
|
||||
}
|
||||
if (pos != 0) {
|
||||
errx(1, ".: lseek(0, SEEK_SET) returned %ld", (long)pos);
|
||||
}
|
||||
|
||||
readit();
|
||||
readit();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readone(const char *shouldbe)
|
||||
{
|
||||
char buf[4096];
|
||||
int len;
|
||||
static void readone(const char *shouldbe) {
|
||||
char buf[4096];
|
||||
int len;
|
||||
|
||||
len = getdirentry(dirfd, buf, sizeof(buf)-1);
|
||||
if (len < 0) {
|
||||
err(1, ".: getdirentry");
|
||||
}
|
||||
if ((unsigned)len >= sizeof(buf)-1) {
|
||||
errx(1, ".: getdirentry returned invalid length %d", len);
|
||||
}
|
||||
buf[len] = 0;
|
||||
len = getdirentry(dirfd, buf, sizeof(buf) - 1);
|
||||
if (len < 0) {
|
||||
err(1, ".: getdirentry");
|
||||
}
|
||||
if ((unsigned)len >= sizeof(buf) - 1) {
|
||||
errx(1, ".: getdirentry returned invalid length %d", len);
|
||||
}
|
||||
buf[len] = 0;
|
||||
|
||||
if (strcmp(buf, shouldbe)) {
|
||||
errx(1, ".: getdirentry returned %s (expected %s)",
|
||||
buf, shouldbe);
|
||||
}
|
||||
if (strcmp(buf, shouldbe)) {
|
||||
errx(1, ".: getdirentry returned %s (expected %s)", buf, shouldbe);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
doreadone(int which)
|
||||
{
|
||||
off_t pos;
|
||||
pos = lseek(dirfd, testfiles[which].pos, SEEK_SET);
|
||||
if (pos<0) {
|
||||
err(1, ".: lseek(%ld, SEEK_SET)", (long) testfiles[which].pos);
|
||||
}
|
||||
if (pos != testfiles[which].pos) {
|
||||
errx(1, ".: lseek(%ld, SEEK_SET) returned %ld",
|
||||
(long) testfiles[which].pos, (long) pos);
|
||||
}
|
||||
static void doreadone(int which) {
|
||||
off_t pos;
|
||||
pos = lseek(dirfd, testfiles[which].pos, SEEK_SET);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(%ld, SEEK_SET)", (long)testfiles[which].pos);
|
||||
}
|
||||
if (pos != testfiles[which].pos) {
|
||||
errx(1, ".: lseek(%ld, SEEK_SET) returned %ld", (long)testfiles[which].pos,
|
||||
(long)pos);
|
||||
}
|
||||
|
||||
readone(testfiles[which].name);
|
||||
readone(testfiles[which].name);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readallonebyone(void)
|
||||
{
|
||||
int i;
|
||||
static void readallonebyone(void) {
|
||||
int i;
|
||||
|
||||
printf("Trying to read each entry again...\n");
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
doreadone(i);
|
||||
}
|
||||
printf("Trying to read each entry again...\n");
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
doreadone(i);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readallrandomly(void)
|
||||
{
|
||||
int n, i, x;
|
||||
static void readallrandomly(void) {
|
||||
int n, i, x;
|
||||
|
||||
printf("Trying to read a bunch of entries randomly...\n");
|
||||
printf("Trying to read a bunch of entries randomly...\n");
|
||||
|
||||
for (i=0; testfiles[i].name; i++);
|
||||
n = i;
|
||||
for (i = 0; testfiles[i].name; i++)
|
||||
;
|
||||
n = i;
|
||||
|
||||
srandom(39584);
|
||||
for (i=0; i<512; i++) {
|
||||
x = (int)(random()%n);
|
||||
doreadone(x);
|
||||
}
|
||||
srandom(39584);
|
||||
for (i = 0; i < 512; i++) {
|
||||
x = (int)(random() % n);
|
||||
doreadone(x);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readateof(void)
|
||||
{
|
||||
char buf[4096];
|
||||
int len;
|
||||
static void readateof(void) {
|
||||
char buf[4096];
|
||||
int len;
|
||||
|
||||
len = getdirentry(dirfd, buf, sizeof(buf)-1);
|
||||
if (len < 0) {
|
||||
err(1, ".: at EOF: getdirentry");
|
||||
}
|
||||
if (len==0) {
|
||||
return;
|
||||
}
|
||||
if ((unsigned)len >= sizeof(buf)-1) {
|
||||
errx(1, ".: at EOF: getdirentry returned "
|
||||
"invalid length %d", len);
|
||||
}
|
||||
buf[len] = 0;
|
||||
errx(1, ".: at EOF: got unexpected name %s", buf);
|
||||
len = getdirentry(dirfd, buf, sizeof(buf) - 1);
|
||||
if (len < 0) {
|
||||
err(1, ".: at EOF: getdirentry");
|
||||
}
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
if ((unsigned)len >= sizeof(buf) - 1) {
|
||||
errx(1,
|
||||
".: at EOF: getdirentry returned "
|
||||
"invalid length %d",
|
||||
len);
|
||||
}
|
||||
buf[len] = 0;
|
||||
errx(1, ".: at EOF: got unexpected name %s", buf);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
doreadateof(void)
|
||||
{
|
||||
off_t pos;
|
||||
int i;
|
||||
static void doreadateof(void) {
|
||||
off_t pos;
|
||||
int i;
|
||||
|
||||
printf("Trying to read after going to EOF...\n");
|
||||
printf("Trying to read after going to EOF...\n");
|
||||
|
||||
pos = lseek(dirfd, 0, SEEK_END);
|
||||
if (pos<0) {
|
||||
err(1, ".: lseek(0, SEEK_END)");
|
||||
}
|
||||
pos = lseek(dirfd, 0, SEEK_END);
|
||||
if (pos < 0) {
|
||||
err(1, ".: lseek(0, SEEK_END)");
|
||||
}
|
||||
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
if (pos <= testfiles[i].pos) {
|
||||
errx(1, ".: EOF position %ld below position %ld of %s",
|
||||
pos, testfiles[i].pos, testfiles[i].name);
|
||||
}
|
||||
}
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
if (pos <= testfiles[i].pos) {
|
||||
errx(1, ".: EOF position %ld below position %ld of %s", pos,
|
||||
testfiles[i].pos, testfiles[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
readateof();
|
||||
readateof();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
inval_read(void)
|
||||
{
|
||||
char buf[4096];
|
||||
int len;
|
||||
static void inval_read(void) {
|
||||
char buf[4096];
|
||||
int len;
|
||||
|
||||
len = getdirentry(dirfd, buf, sizeof(buf)-1);
|
||||
len = getdirentry(dirfd, buf, sizeof(buf) - 1);
|
||||
|
||||
/* Any result is ok, as long as the system doesn't crash */
|
||||
(void)len;
|
||||
/* Any result is ok, as long as the system doesn't crash */
|
||||
(void)len;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dobadreads(void)
|
||||
{
|
||||
off_t pos, pos2, eof;
|
||||
int valid, i, k=0;
|
||||
static void dobadreads(void) {
|
||||
off_t pos, pos2, eof;
|
||||
int valid, i, k = 0;
|
||||
|
||||
printf("Trying some possibly invalid reads...\n");
|
||||
printf("Trying some possibly invalid reads...\n");
|
||||
|
||||
eof = lseek(dirfd, 0, SEEK_END);
|
||||
if (eof < 0) {
|
||||
err(1, ".: lseek(0, SEEK_END)");
|
||||
}
|
||||
eof = lseek(dirfd, 0, SEEK_END);
|
||||
if (eof < 0) {
|
||||
err(1, ".: lseek(0, SEEK_END)");
|
||||
}
|
||||
|
||||
for (pos=0; pos < eof; pos++) {
|
||||
valid = 0;
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
if (pos==testfiles[i].pos) {
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
/* don't try offsets that are known to be valid */
|
||||
continue;
|
||||
}
|
||||
for (pos = 0; pos < eof; pos++) {
|
||||
valid = 0;
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
if (pos == testfiles[i].pos) {
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
/* don't try offsets that are known to be valid */
|
||||
continue;
|
||||
}
|
||||
|
||||
pos2 = lseek(dirfd, pos, SEEK_SET);
|
||||
if (pos2 < 0) {
|
||||
/* this is ok */
|
||||
}
|
||||
else {
|
||||
inval_read();
|
||||
k++;
|
||||
}
|
||||
}
|
||||
pos2 = lseek(dirfd, pos, SEEK_SET);
|
||||
if (pos2 < 0) {
|
||||
/* this is ok */
|
||||
} else {
|
||||
inval_read();
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
if (k>0) {
|
||||
printf("Survived %d invalid reads...\n", k);
|
||||
}
|
||||
else {
|
||||
printf("Couldn't find any invalid offsets to try...\n");
|
||||
}
|
||||
if (k > 0) {
|
||||
printf("Survived %d invalid reads...\n", k);
|
||||
} else {
|
||||
printf("Couldn't find any invalid offsets to try...\n");
|
||||
}
|
||||
|
||||
printf("Trying to read beyond EOF...\n");
|
||||
pos2 = lseek(dirfd, eof + 1000, SEEK_SET);
|
||||
if (pos2 < 0) {
|
||||
/* this is ok */
|
||||
}
|
||||
else {
|
||||
inval_read();
|
||||
}
|
||||
printf("Trying to read beyond EOF...\n");
|
||||
pos2 = lseek(dirfd, eof + 1000, SEEK_SET);
|
||||
if (pos2 < 0) {
|
||||
/* this is ok */
|
||||
} else {
|
||||
inval_read();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dotest(void)
|
||||
{
|
||||
printf("Opening directory...\n");
|
||||
openit();
|
||||
static void dotest(void) {
|
||||
printf("Opening directory...\n");
|
||||
openit();
|
||||
|
||||
printf("Running tests...\n");
|
||||
printf("Running tests...\n");
|
||||
|
||||
/* read the whole directory */
|
||||
firstread();
|
||||
/* read the whole directory */
|
||||
firstread();
|
||||
|
||||
/* make sure eof behaves right */
|
||||
readateof();
|
||||
/* make sure eof behaves right */
|
||||
readateof();
|
||||
|
||||
/* read all the filenames again by seeking */
|
||||
readallonebyone();
|
||||
/* read all the filenames again by seeking */
|
||||
readallonebyone();
|
||||
|
||||
/* try reading at eof */
|
||||
doreadateof();
|
||||
/* try reading at eof */
|
||||
doreadateof();
|
||||
|
||||
/* read a bunch of the filenames over and over again */
|
||||
readallrandomly();
|
||||
/* read a bunch of the filenames over and over again */
|
||||
readallrandomly();
|
||||
|
||||
/* rewind and read the whole thing again, to make sure that works */
|
||||
doreadat0();
|
||||
/* rewind and read the whole thing again, to make sure that works */
|
||||
doreadat0();
|
||||
|
||||
/* do invalid reads */
|
||||
dobadreads();
|
||||
/* do invalid reads */
|
||||
dobadreads();
|
||||
|
||||
/* rewind again to make sure the invalid attempts didn't break it */
|
||||
doreadat0();
|
||||
/* rewind again to make sure the invalid attempts didn't break it */
|
||||
doreadat0();
|
||||
|
||||
printf("Closing directory...\n");
|
||||
closeit();
|
||||
printf("Closing directory...\n");
|
||||
closeit();
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* Setup code */
|
||||
/************************************************************/
|
||||
|
||||
static
|
||||
void
|
||||
mkfile(const char *name)
|
||||
{
|
||||
int fd, i, r;
|
||||
static const char message[] = "The turtle moves!\n";
|
||||
char buf[32*sizeof(message)+1];
|
||||
static void mkfile(const char *name) {
|
||||
int fd, i, r;
|
||||
static const char message[] = "The turtle moves!\n";
|
||||
char buf[32 * sizeof(message) + 1];
|
||||
|
||||
buf[0]=0;
|
||||
for (i=0; i<32; i++) {
|
||||
strcat(buf, message);
|
||||
}
|
||||
buf[0] = 0;
|
||||
for (i = 0; i < 32; i++) {
|
||||
strcat(buf, message);
|
||||
}
|
||||
|
||||
/* Use O_EXCL, because we know the file shouldn't already be there */
|
||||
fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0664);
|
||||
if (fd<0) {
|
||||
err(1, "%s: create", name);
|
||||
}
|
||||
/* Use O_EXCL, because we know the file shouldn't already be there */
|
||||
fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", name);
|
||||
}
|
||||
|
||||
r = write(fd, buf, strlen(buf));
|
||||
if (r<0) {
|
||||
err(1, "%s: write", name);
|
||||
}
|
||||
if ((unsigned)r != strlen(buf)) {
|
||||
errx(1, "%s: short write (%d bytes)", name, r);
|
||||
}
|
||||
r = write(fd, buf, strlen(buf));
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", name);
|
||||
}
|
||||
if ((unsigned)r != strlen(buf)) {
|
||||
errx(1, "%s: short write (%d bytes)", name, r);
|
||||
}
|
||||
|
||||
if (close(fd)<0) {
|
||||
err(1, "%s: close", name);
|
||||
}
|
||||
if (close(fd) < 0) {
|
||||
err(1, "%s: close", name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
setup(void)
|
||||
{
|
||||
int i;
|
||||
static void setup(void) {
|
||||
int i;
|
||||
|
||||
printf("Making directory %s...\n", TESTDIR);
|
||||
printf("Making directory %s...\n", TESTDIR);
|
||||
|
||||
/* Create a directory */
|
||||
if (mkdir(TESTDIR, 0775)<0) {
|
||||
err(1, "%s: mkdir", TESTDIR);
|
||||
}
|
||||
/* Create a directory */
|
||||
if (mkdir(TESTDIR, 0775) < 0) {
|
||||
err(1, "%s: mkdir", TESTDIR);
|
||||
}
|
||||
|
||||
/* Switch to it */
|
||||
if (chdir(TESTDIR)<0) {
|
||||
err(1, "%s: chdir", TESTDIR);
|
||||
}
|
||||
/* Switch to it */
|
||||
if (chdir(TESTDIR) < 0) {
|
||||
err(1, "%s: chdir", TESTDIR);
|
||||
}
|
||||
|
||||
printf("Making some files...\n");
|
||||
printf("Making some files...\n");
|
||||
|
||||
/* Populate it */
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
if (testfiles[i].make_it) {
|
||||
mkfile(testfiles[i].name);
|
||||
}
|
||||
testfiles[i].pos = -1;
|
||||
}
|
||||
/* Populate it */
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
if (testfiles[i].make_it) {
|
||||
mkfile(testfiles[i].name);
|
||||
}
|
||||
testfiles[i].pos = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
int i;
|
||||
static void cleanup(void) {
|
||||
int i;
|
||||
|
||||
printf("Cleaning up...\n");
|
||||
printf("Cleaning up...\n");
|
||||
|
||||
/* Remove the files */
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
if (testfiles[i].make_it) {
|
||||
if (remove(testfiles[i].name)<0) {
|
||||
err(1, "%s: remove", testfiles[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Remove the files */
|
||||
for (i = 0; testfiles[i].name; i++) {
|
||||
if (testfiles[i].make_it) {
|
||||
if (remove(testfiles[i].name) < 0) {
|
||||
err(1, "%s: remove", testfiles[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Leave the dir */
|
||||
if (chdir("..")<0) {
|
||||
err(1, "..: chdir");
|
||||
}
|
||||
/* Leave the dir */
|
||||
if (chdir("..") < 0) {
|
||||
err(1, "..: chdir");
|
||||
}
|
||||
|
||||
/* Remove the dir */
|
||||
if (rmdir(TESTDIR)<0) {
|
||||
err(1, "%s: rmdir", TESTDIR);
|
||||
}
|
||||
/* Remove the dir */
|
||||
if (rmdir(TESTDIR) < 0) {
|
||||
err(1, "%s: rmdir", TESTDIR);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
setup();
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
setup();
|
||||
/* Do the whole thing twice */
|
||||
dotest();
|
||||
dotest();
|
||||
|
||||
/* Do the whole thing twice */
|
||||
dotest();
|
||||
dotest();
|
||||
|
||||
cleanup();
|
||||
return 0;
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,41 +46,38 @@
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
|
||||
#define MAXLEVELS 5
|
||||
#define MAXLEVELS 5
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i;
|
||||
const char *onename = "testdir";
|
||||
char dirname[512];
|
||||
int main(void) {
|
||||
int i;
|
||||
const char *onename = "testdir";
|
||||
char dirname[512];
|
||||
|
||||
strcpy(dirname, onename);
|
||||
strcpy(dirname, onename);
|
||||
|
||||
for (i=0; i<MAXLEVELS; i++) {
|
||||
printf("Creating directory: %s\n", dirname);
|
||||
for (i = 0; i < MAXLEVELS; i++) {
|
||||
printf("Creating directory: %s\n", dirname);
|
||||
|
||||
if (mkdir(dirname, 0755)) {
|
||||
err(1, "%s: mkdir", dirname);
|
||||
}
|
||||
if (mkdir(dirname, 0755)) {
|
||||
err(1, "%s: mkdir", dirname);
|
||||
}
|
||||
|
||||
strcat(dirname, "/");
|
||||
strcat(dirname, onename);
|
||||
}
|
||||
strcat(dirname, "/");
|
||||
strcat(dirname, onename);
|
||||
}
|
||||
|
||||
printf("Passed directory creation test.\n");
|
||||
printf("Passed directory creation test.\n");
|
||||
|
||||
for (i=0; i<MAXLEVELS; i++) {
|
||||
dirname[strlen(dirname) - strlen(onename) - 1] = 0;
|
||||
for (i = 0; i < MAXLEVELS; i++) {
|
||||
dirname[strlen(dirname) - strlen(onename) - 1] = 0;
|
||||
|
||||
printf("Removing directory: %s\n", dirname);
|
||||
printf("Removing directory: %s\n", dirname);
|
||||
|
||||
if (rmdir(dirname)) {
|
||||
err(1, "%s: rmdir", dirname);
|
||||
}
|
||||
}
|
||||
printf("Passed directory removal test.\n");
|
||||
if (rmdir(dirname)) {
|
||||
err(1, "%s: rmdir", dirname);
|
||||
}
|
||||
}
|
||||
printf("Passed directory removal test.\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,14 +41,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define SectorSize 512
|
||||
#define SectorSize 512
|
||||
|
||||
#define TMULT 50
|
||||
#define FSIZE ((SectorSize + 1) * TMULT)
|
||||
#define TMULT 50
|
||||
#define FSIZE ((SectorSize + 1) * TMULT)
|
||||
|
||||
#define FNAME "f-testfile"
|
||||
#define READCHAR 'r'
|
||||
#define WRITECHAR 'w'
|
||||
#define FNAME "f-testfile"
|
||||
#define READCHAR 'r'
|
||||
#define WRITECHAR 'w'
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -57,50 +57,45 @@
|
||||
|
||||
static char buffer[SectorSize + 1];
|
||||
|
||||
static
|
||||
void
|
||||
check_buffer(void)
|
||||
{
|
||||
int i;
|
||||
char ch = buffer[0];
|
||||
static void check_buffer(void) {
|
||||
int i;
|
||||
char ch = buffer[0];
|
||||
|
||||
for (i = 1; i < SectorSize + 1; i++) {
|
||||
if (buffer[i] != ch) {
|
||||
errx(1, "Read error: %s", buffer);
|
||||
}
|
||||
}
|
||||
for (i = 1; i < SectorSize + 1; i++) {
|
||||
if (buffer[i] != ch) {
|
||||
errx(1, "Read error: %s", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
putchar(ch);
|
||||
putchar(ch);
|
||||
}
|
||||
|
||||
void
|
||||
subproc_read(void)
|
||||
{
|
||||
int fd;
|
||||
int i, res;
|
||||
void subproc_read(void) {
|
||||
int fd;
|
||||
int i, res;
|
||||
|
||||
printf("File Reader starting ...\n\n");
|
||||
printf("File Reader starting ...\n\n");
|
||||
|
||||
fd = open(FNAME, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open", FNAME);
|
||||
}
|
||||
fd = open(FNAME, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open", FNAME);
|
||||
}
|
||||
|
||||
for (i=0; i<TMULT; i++) {
|
||||
res = read(fd, buffer, SectorSize + 1);
|
||||
if (res < 0) {
|
||||
err(1, "%s: read", FNAME);
|
||||
}
|
||||
for (i = 0; i < TMULT; i++) {
|
||||
res = read(fd, buffer, SectorSize + 1);
|
||||
if (res < 0) {
|
||||
err(1, "%s: read", FNAME);
|
||||
}
|
||||
|
||||
// yield();
|
||||
// yield();
|
||||
|
||||
if (res != SectorSize + 1) {
|
||||
errx(1, "%s: read: short count", FNAME);
|
||||
}
|
||||
check_buffer();
|
||||
}
|
||||
if (res != SectorSize + 1) {
|
||||
errx(1, "%s: read: short count", FNAME);
|
||||
}
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
|
||||
printf("File Read exited successfully!\n");
|
||||
printf("File Read exited successfully!\n");
|
||||
}
|
||||
|
||||
@@ -48,10 +48,9 @@
|
||||
#include <err.h>
|
||||
#include "f_hdr.h"
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
|
||||
#define BUFFER_SIZE (2 * SECTOR_SIZE + 1)
|
||||
#define BUFFER_SIZE (2 * SECTOR_SIZE + 1)
|
||||
#define BIGFILE_SIZE (270 * BUFFER_SIZE)
|
||||
#define BIGFILE_NAME "large-f"
|
||||
|
||||
@@ -60,289 +59,262 @@
|
||||
char fbuffer[BUFFER_SIZE];
|
||||
char ibuffer[32];
|
||||
|
||||
#define DIR_DEPTH 8
|
||||
#define DIR_NAME "/t"
|
||||
#define DIRFILE_NAME "a"
|
||||
|
||||
#define DIR_DEPTH 8
|
||||
#define DIR_NAME "/t"
|
||||
#define DIRFILE_NAME "a"
|
||||
#define FNAME "f-testfile"
|
||||
#define TMULT 50
|
||||
#define FSIZE ((SECTOR_SIZE + 1) * TMULT)
|
||||
|
||||
|
||||
#define FNAME "f-testfile"
|
||||
#define TMULT 50
|
||||
#define FSIZE ((SECTOR_SIZE + 1) * TMULT)
|
||||
|
||||
#define READCHAR 'r'
|
||||
#define WRITECHAR 'w'
|
||||
#define READCHAR 'r'
|
||||
#define WRITECHAR 'w'
|
||||
|
||||
char cbuffer[SECTOR_SIZE + 1];
|
||||
|
||||
|
||||
/* ===================================================
|
||||
|
||||
*/
|
||||
|
||||
static
|
||||
pid_t
|
||||
forkoff(void (*func)(void))
|
||||
{
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
warn("fork");
|
||||
return -1;
|
||||
case 0:
|
||||
func();
|
||||
_exit(0);
|
||||
default: break;
|
||||
}
|
||||
return pid;
|
||||
static pid_t forkoff(void (*func)(void)) {
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
warn("fork");
|
||||
return -1;
|
||||
case 0:
|
||||
func();
|
||||
_exit(0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dowait(int pid)
|
||||
{
|
||||
int status;
|
||||
static void dowait(int pid) {
|
||||
int status;
|
||||
|
||||
if (waitpid(pid, &status, 0)<0) {
|
||||
warn("waitpid for %d", pid);
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d: signal %d", pid, WTERMSIG(status));
|
||||
}
|
||||
else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d: exit %d", pid, WEXITSTATUS(status));
|
||||
}
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("waitpid for %d", pid);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d: signal %d", pid, WTERMSIG(status));
|
||||
} else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d: exit %d", pid, WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================================================
|
||||
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
big_file(int size)
|
||||
{
|
||||
int i, j, fileid;
|
||||
static void big_file(int size) {
|
||||
int i, j, fileid;
|
||||
|
||||
printf("[BIGFILE] test starting :\n");
|
||||
printf("\tCreating a file of size: %d\n", size);
|
||||
printf("[BIGFILE] test starting :\n");
|
||||
printf("\tCreating a file of size: %d\n", size);
|
||||
|
||||
fileid = open(BIGFILE_NAME, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (fileid < 0) {
|
||||
err(1, "[BIGFILE]: %s: open for write", BIGFILE_NAME);
|
||||
}
|
||||
fileid = open(BIGFILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fileid < 0) {
|
||||
err(1, "[BIGFILE]: %s: open for write", BIGFILE_NAME);
|
||||
}
|
||||
|
||||
for(i = 0; i < BUFFER_SIZE; i++) {
|
||||
fbuffer[i] = LETTER(i);
|
||||
}
|
||||
for (i = 0; i < BUFFER_SIZE; i++) {
|
||||
fbuffer[i] = LETTER(i);
|
||||
}
|
||||
|
||||
printf("\tWriting to file.\n");
|
||||
for (i = 0; i < size; i += BUFFER_SIZE) {
|
||||
write(fileid, fbuffer, BUFFER_SIZE);
|
||||
printf("\tWriting to file.\n");
|
||||
for (i = 0; i < size; i += BUFFER_SIZE) {
|
||||
write(fileid, fbuffer, BUFFER_SIZE);
|
||||
|
||||
if (!(i % (10 * BUFFER_SIZE))) {
|
||||
printf("\rBW : %d", i);
|
||||
}
|
||||
}
|
||||
if (!(i % (10 * BUFFER_SIZE))) {
|
||||
printf("\rBW : %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n\tReading from file.\n");
|
||||
close(fileid);
|
||||
printf("\n\tReading from file.\n");
|
||||
close(fileid);
|
||||
|
||||
fileid = open(BIGFILE_NAME, O_RDONLY);
|
||||
if (fileid < 0) {
|
||||
err(1, "[BIGFILE]: %s: open for read", BIGFILE_NAME);
|
||||
}
|
||||
fileid = open(BIGFILE_NAME, O_RDONLY);
|
||||
if (fileid < 0) {
|
||||
err(1, "[BIGFILE]: %s: open for read", BIGFILE_NAME);
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += BUFFER_SIZE) {
|
||||
j = read(fileid, fbuffer, BUFFER_SIZE);
|
||||
if (j<0) {
|
||||
err(1, "[BIGFILE]: read");
|
||||
}
|
||||
if (j != BUFFER_SIZE) {
|
||||
errx(1, "[BIGFILE]: read: only %d bytes", j);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < size; i += BUFFER_SIZE) {
|
||||
j = read(fileid, fbuffer, BUFFER_SIZE);
|
||||
if (j < 0) {
|
||||
err(1, "[BIGFILE]: read");
|
||||
}
|
||||
if (j != BUFFER_SIZE) {
|
||||
errx(1, "[BIGFILE]: read: only %d bytes", j);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(i % (10 * BUFFER_SIZE))) {
|
||||
printf("\rBR : %d", i);
|
||||
}
|
||||
if (!(i % (10 * BUFFER_SIZE))) {
|
||||
printf("\rBR : %d", i);
|
||||
}
|
||||
|
||||
/* Check to see that the data is consistent : */
|
||||
for (j = 0; j < BUFFER_SIZE; j++) {
|
||||
if (fbuffer[j] != LETTER(j)) {
|
||||
errx(1, "[BIGFILE] : Failed read check : "
|
||||
"inconsistent data read: %d", i+j);
|
||||
}
|
||||
}
|
||||
/* Check to see that the data is consistent : */
|
||||
for (j = 0; j < BUFFER_SIZE; j++) {
|
||||
if (fbuffer[j] != LETTER(j)) {
|
||||
errx(1,
|
||||
"[BIGFILE] : Failed read check : "
|
||||
"inconsistent data read: %d",
|
||||
i + j);
|
||||
}
|
||||
}
|
||||
|
||||
close(fileid);
|
||||
if (remove(BIGFILE_NAME)) {
|
||||
err(1, "[BIGFILE]: %s: remove", BIGFILE_NAME);
|
||||
}
|
||||
|
||||
close(fileid);
|
||||
if (remove(BIGFILE_NAME)) {
|
||||
err(1, "[BIGFILE]: %s: remove", BIGFILE_NAME);
|
||||
}
|
||||
|
||||
printf("\n[BIGFILE] : Success!\n");
|
||||
printf("\n[BIGFILE] : Success!\n");
|
||||
}
|
||||
|
||||
/* ===================================================
|
||||
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
concur(void)
|
||||
{
|
||||
int i, fd;
|
||||
int r1, r2, w1;
|
||||
static void concur(void) {
|
||||
int i, fd;
|
||||
int r1, r2, w1;
|
||||
|
||||
printf("Spawning 2 readers, 1 writer.\n");
|
||||
printf("Spawning 2 readers, 1 writer.\n");
|
||||
|
||||
fd = open(FNAME, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "[CONCUR]: %s: open", FNAME);
|
||||
}
|
||||
|
||||
fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "[CONCUR]: %s: open", FNAME);
|
||||
}
|
||||
printf("Initializing test file: ");
|
||||
|
||||
printf("Initializing test file: ");
|
||||
for (i = 0; i < SECTOR_SIZE + 1; i++) {
|
||||
cbuffer[i] = READCHAR;
|
||||
}
|
||||
|
||||
for (i = 0; i < SECTOR_SIZE + 1; i++) {
|
||||
cbuffer[i] = READCHAR;
|
||||
}
|
||||
for (i = 0; i < TMULT; i++) {
|
||||
write(fd, cbuffer, SECTOR_SIZE + 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < TMULT; i++) {
|
||||
write(fd, cbuffer, SECTOR_SIZE + 1);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
printf("Done initializing. Starting processes...\n");
|
||||
|
||||
close(fd);
|
||||
r1 = forkoff(subproc_read);
|
||||
w1 = forkoff(subproc_write);
|
||||
r2 = forkoff(subproc_read);
|
||||
|
||||
printf("Done initializing. Starting processes...\n");
|
||||
printf("Waiting for processes.\n");
|
||||
|
||||
r1 = forkoff(subproc_read);
|
||||
w1 = forkoff(subproc_write);
|
||||
r2 = forkoff(subproc_read);
|
||||
dowait(r1);
|
||||
dowait(r2);
|
||||
dowait(w1);
|
||||
|
||||
printf("Waiting for processes.\n");
|
||||
if (remove(FNAME)) {
|
||||
err(1, "[CONCUR]: %s: remove", FNAME);
|
||||
}
|
||||
|
||||
dowait(r1);
|
||||
dowait(r2);
|
||||
dowait(w1);
|
||||
|
||||
if (remove(FNAME)) {
|
||||
err(1, "[CONCUR]: %s: remove", FNAME);
|
||||
}
|
||||
|
||||
printf("[CONCUR] Done!\n");
|
||||
printf("[CONCUR] Done!\n");
|
||||
}
|
||||
|
||||
/* ===================================================
|
||||
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
dir_test(int depth)
|
||||
{
|
||||
int i, fd;
|
||||
char tmp[] = DIR_NAME;
|
||||
char fmp[] = DIRFILE_NAME;
|
||||
char dirname[64];
|
||||
static void dir_test(int depth) {
|
||||
int i, fd;
|
||||
char tmp[] = DIR_NAME;
|
||||
char fmp[] = DIRFILE_NAME;
|
||||
char dirname[64];
|
||||
|
||||
strcpy(dirname, ".");
|
||||
strcpy(dirname, ".");
|
||||
|
||||
for (i = 0; i < depth; i++) {
|
||||
strcat(dirname, tmp);
|
||||
for (i = 0; i < depth; i++) {
|
||||
strcat(dirname, tmp);
|
||||
|
||||
printf("\tCreating dir : %s\n", dirname);
|
||||
printf("\tCreating dir : %s\n", dirname);
|
||||
|
||||
if (mkdir(dirname, 0775) < 0) {
|
||||
err(1, "[DIRTEST]: %s: mkdir", dirname);
|
||||
}
|
||||
if (mkdir(dirname, 0775) < 0) {
|
||||
err(1, "[DIRTEST]: %s: mkdir", dirname);
|
||||
}
|
||||
|
||||
strcat(dirname, fmp);
|
||||
printf("\tCreating file: %s\n", dirname);
|
||||
strcat(dirname, fmp);
|
||||
printf("\tCreating file: %s\n", dirname);
|
||||
|
||||
fd = open(dirname, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd<0) {
|
||||
err(1, "[DIRTEST]: %s: open", dirname);
|
||||
}
|
||||
fd = open(dirname, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "[DIRTEST]: %s: open", dirname);
|
||||
}
|
||||
|
||||
dirname[strlen(dirname) - strlen(fmp)] = '\0';
|
||||
}
|
||||
dirname[strlen(dirname) - strlen(fmp)] = '\0';
|
||||
}
|
||||
|
||||
printf("[DIRTEST] : Passed directory creation test.\n");
|
||||
printf("[DIRTEST] : Passed directory creation test.\n");
|
||||
|
||||
for (i = 0; i < depth; i++) {
|
||||
strcat(dirname, fmp);
|
||||
for (i = 0; i < depth; i++) {
|
||||
strcat(dirname, fmp);
|
||||
|
||||
printf("\tDeleting file: %s\n", dirname);
|
||||
printf("\tDeleting file: %s\n", dirname);
|
||||
|
||||
if (remove(dirname)) {
|
||||
err(1, "[DIRTEST]: %s: remove", dirname);
|
||||
}
|
||||
if (remove(dirname)) {
|
||||
err(1, "[DIRTEST]: %s: remove", dirname);
|
||||
}
|
||||
|
||||
dirname[strlen(dirname) - strlen(fmp)] = '\0';
|
||||
printf("\tRemoving dir : %s\n", dirname);
|
||||
dirname[strlen(dirname) - strlen(fmp)] = '\0';
|
||||
printf("\tRemoving dir : %s\n", dirname);
|
||||
|
||||
if (rmdir(dirname)) {
|
||||
err(1, "[DIRTEST]: %s: rmdir", dirname);
|
||||
}
|
||||
if (rmdir(dirname)) {
|
||||
err(1, "[DIRTEST]: %s: rmdir", dirname);
|
||||
}
|
||||
|
||||
dirname[strlen(dirname) - strlen(tmp)] = '\0';
|
||||
}
|
||||
dirname[strlen(dirname) - strlen(tmp)] = '\0';
|
||||
}
|
||||
|
||||
printf("[DIRTEST] : Passed directory removal test.\n");
|
||||
printf("[DIRTEST] : Success!\n");
|
||||
printf("[DIRTEST] : Passed directory removal test.\n");
|
||||
printf("[DIRTEST] : Success!\n");
|
||||
}
|
||||
|
||||
/* ===================================================
|
||||
|
||||
*/
|
||||
|
||||
#define RUNBIGFILE 0x1
|
||||
#define RUNDIRTEST 0x2
|
||||
#define RUNCONCUR 0x4
|
||||
#define RUNTHEMALL (RUNBIGFILE | RUNDIRTEST | RUNCONCUR)
|
||||
#define RUNBIGFILE 0x1
|
||||
#define RUNDIRTEST 0x2
|
||||
#define RUNCONCUR 0x4
|
||||
#define RUNTHEMALL (RUNBIGFILE | RUNDIRTEST | RUNCONCUR)
|
||||
|
||||
int
|
||||
main(int argc, char * argv[])
|
||||
{
|
||||
int tv = 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
int tv = 0;
|
||||
|
||||
if (argc > 1) {
|
||||
if (*argv[1]=='1') {
|
||||
tv = RUNBIGFILE;
|
||||
}
|
||||
else if (*argv[1]=='2') {
|
||||
tv = RUNDIRTEST;
|
||||
}
|
||||
else if (*argv[1]=='3') {
|
||||
tv = RUNCONCUR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
tv = RUNTHEMALL;
|
||||
}
|
||||
if (argc > 1) {
|
||||
if (*argv[1] == '1') {
|
||||
tv = RUNBIGFILE;
|
||||
} else if (*argv[1] == '2') {
|
||||
tv = RUNDIRTEST;
|
||||
} else if (*argv[1] == '3') {
|
||||
tv = RUNCONCUR;
|
||||
}
|
||||
} else {
|
||||
tv = RUNTHEMALL;
|
||||
}
|
||||
|
||||
if (tv & RUNBIGFILE) {
|
||||
printf("[BIGFILE] : Run #1\n");
|
||||
big_file(BIGFILE_SIZE);
|
||||
printf("[BIGFILE] : Run #2\n");
|
||||
big_file(BIGFILE_SIZE);
|
||||
}
|
||||
if (tv & RUNBIGFILE) {
|
||||
printf("[BIGFILE] : Run #1\n");
|
||||
big_file(BIGFILE_SIZE);
|
||||
printf("[BIGFILE] : Run #2\n");
|
||||
big_file(BIGFILE_SIZE);
|
||||
}
|
||||
|
||||
if (tv & RUNDIRTEST) {
|
||||
printf("[DIRTEST] : Run #1\n");
|
||||
dir_test(DIR_DEPTH);
|
||||
printf("[DIRTEST] : Run #2\n");
|
||||
dir_test(DIR_DEPTH);
|
||||
}
|
||||
if (tv & RUNDIRTEST) {
|
||||
printf("[DIRTEST] : Run #1\n");
|
||||
dir_test(DIR_DEPTH);
|
||||
printf("[DIRTEST] : Run #2\n");
|
||||
dir_test(DIR_DEPTH);
|
||||
}
|
||||
|
||||
if (tv & RUNCONCUR) {
|
||||
printf("[CONCUR]\n");
|
||||
concur();
|
||||
}
|
||||
return 0;
|
||||
if (tv & RUNCONCUR) {
|
||||
printf("[CONCUR]\n");
|
||||
concur();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,14 +41,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define SectorSize 512
|
||||
#define SectorSize 512
|
||||
|
||||
#define TMULT 50
|
||||
#define FSIZE ((SectorSize + 1) * TMULT)
|
||||
#define TMULT 50
|
||||
#define FSIZE ((SectorSize + 1) * TMULT)
|
||||
|
||||
#define FNAME "f-testfile"
|
||||
#define READCHAR 'r'
|
||||
#define WRITECHAR 'w'
|
||||
#define FNAME "f-testfile"
|
||||
#define READCHAR 'r'
|
||||
#define WRITECHAR 'w'
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
@@ -57,29 +57,27 @@
|
||||
|
||||
static char buffer[SectorSize + 1];
|
||||
|
||||
void
|
||||
subproc_write(void)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
void subproc_write(void) {
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
for (i=0; i < SectorSize + 1; i++) {
|
||||
buffer[i] = WRITECHAR;
|
||||
}
|
||||
for (i = 0; i < SectorSize + 1; i++) {
|
||||
buffer[i] = WRITECHAR;
|
||||
}
|
||||
|
||||
printf("File Writer starting ...\n");
|
||||
printf("File Writer starting ...\n");
|
||||
|
||||
fd = open(FNAME, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open", FNAME);
|
||||
}
|
||||
fd = open(FNAME, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open", FNAME);
|
||||
}
|
||||
|
||||
for (i=0; i<TMULT; i++) {
|
||||
// yield();
|
||||
write(fd, buffer, SectorSize + 1);
|
||||
}
|
||||
for (i = 0; i < TMULT; i++) {
|
||||
// yield();
|
||||
write(fd, buffer, SectorSize + 1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
|
||||
printf("File Write exited successfully!\n");
|
||||
printf("File Write exited successfully!\n");
|
||||
}
|
||||
|
||||
@@ -57,207 +57,178 @@
|
||||
|
||||
#define NUMSIZE 8191
|
||||
struct number {
|
||||
char buf[NUMSIZE+1]; /* includes space for a null-terminator */
|
||||
size_t first; /* first valid digit */
|
||||
char buf[NUMSIZE + 1]; /* includes space for a null-terminator */
|
||||
size_t first; /* first valid digit */
|
||||
};
|
||||
|
||||
static struct number scratch;
|
||||
|
||||
static
|
||||
void
|
||||
number_init(struct number *n, const char *txt)
|
||||
{
|
||||
size_t len, i;
|
||||
static void number_init(struct number *n, const char *txt) {
|
||||
size_t len, i;
|
||||
|
||||
len = strlen(txt);
|
||||
if (len > NUMSIZE) {
|
||||
warnx("%s", txt);
|
||||
errx(1, "Number too large");
|
||||
}
|
||||
n->first = NUMSIZE - len;
|
||||
strcpy(n->buf + n->first, txt);
|
||||
len = strlen(txt);
|
||||
if (len > NUMSIZE) {
|
||||
warnx("%s", txt);
|
||||
errx(1, "Number too large");
|
||||
}
|
||||
n->first = NUMSIZE - len;
|
||||
strcpy(n->buf + n->first, txt);
|
||||
#if 0
|
||||
for (i=0; i<n->first; i++) {
|
||||
n->buf[i] = '0';
|
||||
}
|
||||
#endif
|
||||
for (i=n->first; i<NUMSIZE; i++) {
|
||||
if (n->buf[i] < '0' || n->buf[i] > '9') {
|
||||
warnx("%s", txt);
|
||||
errx(1, "Number contained non-digit characters");
|
||||
}
|
||||
}
|
||||
assert(n->buf[NUMSIZE] == 0);
|
||||
while (n->first < NUMSIZE && n->buf[n->first] == '0') {
|
||||
n->first++;
|
||||
}
|
||||
for (i = n->first; i < NUMSIZE; i++) {
|
||||
if (n->buf[i] < '0' || n->buf[i] > '9') {
|
||||
warnx("%s", txt);
|
||||
errx(1, "Number contained non-digit characters");
|
||||
}
|
||||
}
|
||||
assert(n->buf[NUMSIZE] == 0);
|
||||
while (n->first < NUMSIZE && n->buf[n->first] == '0') {
|
||||
n->first++;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
char *
|
||||
number_get(struct number *n)
|
||||
{
|
||||
size_t pos;
|
||||
static char *number_get(struct number *n) {
|
||||
size_t pos;
|
||||
|
||||
pos = n->first;
|
||||
while (pos < NUMSIZE && n->buf[pos] == '0') {
|
||||
pos++;
|
||||
}
|
||||
if (pos == NUMSIZE) {
|
||||
pos--;
|
||||
n->buf[pos] = '0';
|
||||
}
|
||||
return &n->buf[pos];
|
||||
pos = n->first;
|
||||
while (pos < NUMSIZE && n->buf[pos] == '0') {
|
||||
pos++;
|
||||
}
|
||||
if (pos == NUMSIZE) {
|
||||
pos--;
|
||||
n->buf[pos] = '0';
|
||||
}
|
||||
return &n->buf[pos];
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
finishcarry(struct number *r, const struct number *b, size_t pos,
|
||||
unsigned carry)
|
||||
{
|
||||
if (carry > 0 && b->first == 0) {
|
||||
/* if b->first is 0, pos may now be 2^32-1 */
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
while (carry > 0) {
|
||||
if (pos == 0) {
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
r->buf[pos--] = carry % 10 + '0';
|
||||
carry = carry / 10;
|
||||
}
|
||||
r->first = pos + 1;
|
||||
static void finishcarry(struct number *r, const struct number *b, size_t pos,
|
||||
unsigned carry) {
|
||||
if (carry > 0 && b->first == 0) {
|
||||
/* if b->first is 0, pos may now be 2^32-1 */
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
while (carry > 0) {
|
||||
if (pos == 0) {
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
r->buf[pos--] = carry % 10 + '0';
|
||||
carry = carry / 10;
|
||||
}
|
||||
r->first = pos + 1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
pluseq(struct number *r, const struct number *b)
|
||||
{
|
||||
size_t pos;
|
||||
unsigned an, bn, rn, carry;
|
||||
static void pluseq(struct number *r, const struct number *b) {
|
||||
size_t pos;
|
||||
unsigned an, bn, rn, carry;
|
||||
|
||||
carry = 0;
|
||||
for (pos = NUMSIZE; pos-- > b->first; ) {
|
||||
an = pos < r->first ? 0 : r->buf[pos] - '0';
|
||||
bn = b->buf[pos] - '0';
|
||||
rn = an + bn + carry;
|
||||
r->buf[pos] = rn % 10 + '0';
|
||||
carry = rn / 10;
|
||||
}
|
||||
finishcarry(r, b, pos, carry);
|
||||
carry = 0;
|
||||
for (pos = NUMSIZE; pos-- > b->first;) {
|
||||
an = pos < r->first ? 0 : r->buf[pos] - '0';
|
||||
bn = b->buf[pos] - '0';
|
||||
rn = an + bn + carry;
|
||||
r->buf[pos] = rn % 10 + '0';
|
||||
carry = rn / 10;
|
||||
}
|
||||
finishcarry(r, b, pos, carry);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dec(struct number *r)
|
||||
{
|
||||
size_t pos;
|
||||
static void dec(struct number *r) {
|
||||
size_t pos;
|
||||
|
||||
for (pos = NUMSIZE; pos-- > r->first; ) {
|
||||
if (r->buf[pos] == '0') {
|
||||
r->buf[pos] = '9';
|
||||
}
|
||||
else {
|
||||
r->buf[pos]--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* This should really not happen. */
|
||||
errx(1, "Underflow");
|
||||
for (pos = NUMSIZE; pos-- > r->first;) {
|
||||
if (r->buf[pos] == '0') {
|
||||
r->buf[pos] = '9';
|
||||
} else {
|
||||
r->buf[pos]--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* This should really not happen. */
|
||||
errx(1, "Underflow");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
multc(struct number *r, const struct number *a, unsigned bn, size_t offset)
|
||||
{
|
||||
size_t pos;
|
||||
unsigned an, rn, carry;
|
||||
static void multc(struct number *r, const struct number *a, unsigned bn,
|
||||
size_t offset) {
|
||||
size_t pos;
|
||||
unsigned an, rn, carry;
|
||||
|
||||
for (pos = NUMSIZE; pos-- > NUMSIZE - offset; ) {
|
||||
r->buf[pos] = '0';
|
||||
}
|
||||
carry = 0;
|
||||
for (pos = NUMSIZE; pos-- > a->first; ) {
|
||||
an = a->buf[pos] - '0';
|
||||
rn = an * bn + carry;
|
||||
if (pos < offset) {
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
r->buf[pos - offset] = rn % 10 + '0';
|
||||
carry = rn / 10;
|
||||
}
|
||||
if (carry > 0 && pos < offset) {
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
finishcarry(r, a, pos - offset, carry);
|
||||
for (pos = NUMSIZE; pos-- > NUMSIZE - offset;) {
|
||||
r->buf[pos] = '0';
|
||||
}
|
||||
carry = 0;
|
||||
for (pos = NUMSIZE; pos-- > a->first;) {
|
||||
an = a->buf[pos] - '0';
|
||||
rn = an * bn + carry;
|
||||
if (pos < offset) {
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
r->buf[pos - offset] = rn % 10 + '0';
|
||||
carry = rn / 10;
|
||||
}
|
||||
if (carry > 0 && pos < offset) {
|
||||
errx(1, "Overflow");
|
||||
}
|
||||
finishcarry(r, a, pos - offset, carry);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mult(struct number *r, const struct number *a, const struct number *b)
|
||||
{
|
||||
unsigned offset;
|
||||
size_t apos;
|
||||
static void mult(struct number *r, const struct number *a,
|
||||
const struct number *b) {
|
||||
unsigned offset;
|
||||
size_t apos;
|
||||
|
||||
/* B should normally be the larger number */
|
||||
if (a->first < b->first) {
|
||||
mult(r, b, a);
|
||||
return;
|
||||
}
|
||||
/* B should normally be the larger number */
|
||||
if (a->first < b->first) {
|
||||
mult(r, b, a);
|
||||
return;
|
||||
}
|
||||
|
||||
number_init(&scratch, "0");
|
||||
offset = 0;
|
||||
for (apos = NUMSIZE; apos-- > a->first; ) {
|
||||
multc(&scratch, b, a->buf[apos] - '0', offset);
|
||||
pluseq(r, &scratch);
|
||||
offset++;
|
||||
}
|
||||
number_init(&scratch, "0");
|
||||
offset = 0;
|
||||
for (apos = NUMSIZE; apos-- > a->first;) {
|
||||
multc(&scratch, b, a->buf[apos] - '0', offset);
|
||||
pluseq(r, &scratch);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// argv logic
|
||||
|
||||
static
|
||||
void
|
||||
self(const char *arg1, const char *arg2)
|
||||
{
|
||||
const char *args[4];
|
||||
static void self(const char *arg1, const char *arg2) {
|
||||
const char *args[4];
|
||||
|
||||
args[0] = _PATH_SELF;
|
||||
args[1] = arg1;
|
||||
args[2] = arg2;
|
||||
args[3] = NULL;
|
||||
execv(_PATH_SELF, (char **)args);
|
||||
err(1, "execv");
|
||||
args[0] = _PATH_SELF;
|
||||
args[1] = arg1;
|
||||
args[2] = arg2;
|
||||
args[3] = NULL;
|
||||
execv(_PATH_SELF, (char **)args);
|
||||
err(1, "execv");
|
||||
}
|
||||
|
||||
static struct number n1, n2, multbuf;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc == 0) {
|
||||
/* Assume we've just been run from the menu. */
|
||||
self("404", "1");
|
||||
}
|
||||
else if (argc == 2) {
|
||||
self(argv[1], "1");
|
||||
}
|
||||
else if (argc == 3) {
|
||||
if (!strcmp(argv[1], "1") || !strcmp(argv[1], "0")) {
|
||||
printf("%s\n", argv[2]);
|
||||
}
|
||||
else {
|
||||
number_init(&n1, argv[1]);
|
||||
number_init(&n2, argv[2]);
|
||||
number_init(&multbuf, "0");
|
||||
mult(&multbuf, &n1, &n2);
|
||||
dec(&n1);
|
||||
self(number_get(&n1), number_get(&multbuf));
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnx("Usage: factorial N");
|
||||
}
|
||||
return 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc == 0) {
|
||||
/* Assume we've just been run from the menu. */
|
||||
self("404", "1");
|
||||
} else if (argc == 2) {
|
||||
self(argv[1], "1");
|
||||
} else if (argc == 3) {
|
||||
if (!strcmp(argv[1], "1") || !strcmp(argv[1], "0")) {
|
||||
printf("%s\n", argv[2]);
|
||||
} else {
|
||||
number_init(&n1, argv[1]);
|
||||
number_init(&n2, argv[2]);
|
||||
number_init(&multbuf, "0");
|
||||
mult(&multbuf, &n1, &n2);
|
||||
dec(&n1);
|
||||
self(number_get(&n1), number_get(&multbuf));
|
||||
}
|
||||
} else {
|
||||
warnx("Usage: factorial N");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,72 +40,52 @@
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
|
||||
static char *hargv[2] = { (char *)"hog", NULL };
|
||||
static char *cargv[3] = { (char *)"cat", (char *)"catfile", NULL };
|
||||
static char *hargv[2] = {(char *)"hog", NULL};
|
||||
static char *cargv[3] = {(char *)"cat", (char *)"catfile", NULL};
|
||||
|
||||
#define MAXPROCS 6
|
||||
#define MAXPROCS 6
|
||||
static int pids[MAXPROCS], npids;
|
||||
|
||||
static
|
||||
void
|
||||
spawnv(const char *prog, char **argv)
|
||||
{
|
||||
int pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
err(1, "fork");
|
||||
case 0:
|
||||
/* child */
|
||||
execv(prog, argv);
|
||||
err(1, "%s", prog);
|
||||
default:
|
||||
/* parent */
|
||||
pids[npids++] = pid;
|
||||
break;
|
||||
}
|
||||
static void spawnv(const char *prog, char **argv) {
|
||||
int pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
err(1, "fork");
|
||||
case 0:
|
||||
/* child */
|
||||
execv(prog, argv);
|
||||
err(1, "%s", prog);
|
||||
default:
|
||||
/* parent */
|
||||
pids[npids++] = pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
waitall(void)
|
||||
{
|
||||
int i, status;
|
||||
for (i=0; i<npids; i++) {
|
||||
if (waitpid(pids[i], &status, 0)<0) {
|
||||
warn("waitpid for %d", pids[i]);
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d: signal %d", pids[i], WTERMSIG(status));
|
||||
}
|
||||
else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d: exit %d", pids[i], WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
static void waitall(void) {
|
||||
int i, status;
|
||||
for (i = 0; i < npids; i++) {
|
||||
if (waitpid(pids[i], &status, 0) < 0) {
|
||||
warn("waitpid for %d", pids[i]);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d: signal %d", pids[i], WTERMSIG(status));
|
||||
} else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d: exit %d", pids[i], WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
hog(void)
|
||||
{
|
||||
spawnv("/testbin/hog", hargv);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
cat(void)
|
||||
{
|
||||
spawnv("/bin/cat", cargv);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
hog();
|
||||
hog();
|
||||
hog();
|
||||
cat();
|
||||
|
||||
waitall();
|
||||
|
||||
return 0;
|
||||
static void hog(void) { spawnv("/testbin/hog", hargv); }
|
||||
|
||||
static void cat(void) { spawnv("/bin/cat", cargv); }
|
||||
|
||||
int main(void) {
|
||||
hog();
|
||||
hog();
|
||||
hog();
|
||||
cat();
|
||||
|
||||
waitall();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,19 +38,17 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define REALLY_BIG_ADDRESS 0x40000000
|
||||
#define REALLY_BIG_ADDRESS 0x40000000
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
volatile int i;
|
||||
int main(void) {
|
||||
volatile int i;
|
||||
|
||||
printf("\nEntering the faulter program - I should die immediately\n");
|
||||
i = *(int *)REALLY_BIG_ADDRESS;
|
||||
printf("\nEntering the faulter program - I should die immediately\n");
|
||||
i = *(int *)REALLY_BIG_ADDRESS;
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)i;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)i;
|
||||
|
||||
printf("I didn't get killed! Program has a bug\n");
|
||||
return 0;
|
||||
printf("I didn't get killed! Program has a bug\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,66 +43,61 @@
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
static char writebuf[41] = "Twiddle dee dee, Twiddle dum dum.......\n";
|
||||
static char readbuf[41];
|
||||
int main(int argc, char *argv[]) {
|
||||
static char writebuf[41] = "Twiddle dee dee, Twiddle dum dum.......\n";
|
||||
static char readbuf[41];
|
||||
|
||||
const char *file;
|
||||
int fd, rv;
|
||||
const char *file;
|
||||
int fd, rv;
|
||||
|
||||
if (argc == 0) {
|
||||
warnx("No arguments - running on \"testfile\"");
|
||||
file = "testfile";
|
||||
}
|
||||
else if (argc == 2) {
|
||||
file = argv[1];
|
||||
}
|
||||
else {
|
||||
errx(1, "Usage: filetest <filename>");
|
||||
}
|
||||
if (argc == 0) {
|
||||
warnx("No arguments - running on \"testfile\"");
|
||||
file = "testfile";
|
||||
} else if (argc == 2) {
|
||||
file = argv[1];
|
||||
} else {
|
||||
errx(1, "Usage: filetest <filename>");
|
||||
}
|
||||
|
||||
fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd<0) {
|
||||
err(1, "%s: open for write", file);
|
||||
}
|
||||
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open for write", file);
|
||||
}
|
||||
|
||||
rv = write(fd, writebuf, 40);
|
||||
if (rv < 0) {
|
||||
err(1, "%s: write", file);
|
||||
}
|
||||
|
||||
rv = write(fd, writebuf, 40);
|
||||
if (rv<0) {
|
||||
err(1, "%s: write", file);
|
||||
}
|
||||
rv = close(fd);
|
||||
if (rv < 0) {
|
||||
err(1, "%s: close (1st time)", file);
|
||||
}
|
||||
|
||||
rv = close(fd);
|
||||
if (rv<0) {
|
||||
err(1, "%s: close (1st time)", file);
|
||||
}
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open for read", file);
|
||||
}
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, "%s: open for read", file);
|
||||
}
|
||||
rv = read(fd, readbuf, 40);
|
||||
if (rv < 0) {
|
||||
err(1, "%s: read", file);
|
||||
}
|
||||
rv = close(fd);
|
||||
if (rv < 0) {
|
||||
err(1, "%s: close (2nd time)", file);
|
||||
}
|
||||
/* ensure null termination */
|
||||
readbuf[40] = 0;
|
||||
|
||||
rv = read(fd, readbuf, 40);
|
||||
if (rv<0) {
|
||||
err(1, "%s: read", file);
|
||||
}
|
||||
rv = close(fd);
|
||||
if (rv<0) {
|
||||
err(1, "%s: close (2nd time)", file);
|
||||
}
|
||||
/* ensure null termination */
|
||||
readbuf[40] = 0;
|
||||
if (strcmp(readbuf, writebuf)) {
|
||||
errx(1, "Buffer data mismatch!");
|
||||
}
|
||||
|
||||
if (strcmp(readbuf, writebuf)) {
|
||||
errx(1, "Buffer data mismatch!");
|
||||
}
|
||||
|
||||
rv = remove(file);
|
||||
if (rv<0) {
|
||||
err(1, "%s: remove", file);
|
||||
}
|
||||
printf("Passed filetest.\n");
|
||||
return 0;
|
||||
rv = remove(file);
|
||||
if (rv < 0) {
|
||||
err(1, "%s: remove", file);
|
||||
}
|
||||
printf("Passed filetest.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -52,25 +52,24 @@
|
||||
|
||||
static volatile int pid;
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i;
|
||||
int main(void) {
|
||||
int i;
|
||||
|
||||
while (1) {
|
||||
fork();
|
||||
while (1) {
|
||||
fork();
|
||||
|
||||
pid = getpid();
|
||||
pid = getpid();
|
||||
|
||||
/* Make sure each fork has its own address space. */
|
||||
for (i=0; i<300; i++) {
|
||||
volatile int seenpid;
|
||||
seenpid = pid;
|
||||
if (seenpid != getpid()) {
|
||||
errx(1, "pid mismatch (%d, should be %d) "
|
||||
"- your vm is broken!",
|
||||
seenpid, getpid());
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Make sure each fork has its own address space. */
|
||||
for (i = 0; i < 300; i++) {
|
||||
volatile int seenpid;
|
||||
seenpid = pid;
|
||||
if (seenpid != getpid()) {
|
||||
errx(1,
|
||||
"pid mismatch (%d, should be %d) "
|
||||
"- your vm is broken!",
|
||||
seenpid, getpid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,16 +51,13 @@ static volatile int mypid;
|
||||
/*
|
||||
* Helper function for fork that prints a warning on error.
|
||||
*/
|
||||
static
|
||||
int
|
||||
dofork(void)
|
||||
{
|
||||
int pid;
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
warn("fork");
|
||||
}
|
||||
return pid;
|
||||
static int dofork(void) {
|
||||
int pid;
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
warn("fork");
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -68,24 +65,22 @@ dofork(void)
|
||||
* the pid into the data segment and read it back repeatedly, making
|
||||
* sure it's correct every time.
|
||||
*/
|
||||
static
|
||||
void
|
||||
check(void)
|
||||
{
|
||||
int i;
|
||||
static void check(void) {
|
||||
int i;
|
||||
|
||||
mypid = getpid();
|
||||
mypid = getpid();
|
||||
|
||||
/* Make sure each fork has its own address space. */
|
||||
for (i=0; i<800; i++) {
|
||||
volatile int seenpid;
|
||||
seenpid = mypid;
|
||||
if (seenpid != getpid()) {
|
||||
errx(1, "pid mismatch (%d, should be %d) "
|
||||
"- your vm is broken!",
|
||||
seenpid, getpid());
|
||||
}
|
||||
}
|
||||
/* Make sure each fork has its own address space. */
|
||||
for (i = 0; i < 800; i++) {
|
||||
volatile int seenpid;
|
||||
seenpid = mypid;
|
||||
if (seenpid != getpid()) {
|
||||
errx(1,
|
||||
"pid mismatch (%d, should be %d) "
|
||||
"- your vm is broken!",
|
||||
seenpid, getpid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -97,121 +92,109 @@ check(void)
|
||||
* generated the current process; that means it's time to exit. Only
|
||||
* the parent of all the processes returns from the chain of dowaits.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dowait(int nowait, int pid)
|
||||
{
|
||||
int x;
|
||||
static void dowait(int nowait, int pid) {
|
||||
int x;
|
||||
|
||||
if (pid<0) {
|
||||
/* fork in question failed; just return */
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
/* in the fork in question we were the child; exit */
|
||||
exit(0);
|
||||
}
|
||||
if (pid < 0) {
|
||||
/* fork in question failed; just return */
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* in the fork in question we were the child; exit */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!nowait) {
|
||||
if (waitpid(pid, &x, 0)<0) {
|
||||
warn("waitpid");
|
||||
}
|
||||
else if (WIFSIGNALED(x)) {
|
||||
warnx("pid %d: signal %d", pid, WTERMSIG(x));
|
||||
}
|
||||
else if (WEXITSTATUS(x) != 0) {
|
||||
warnx("pid %d: exit %d", pid, WEXITSTATUS(x));
|
||||
}
|
||||
}
|
||||
if (!nowait) {
|
||||
if (waitpid(pid, &x, 0) < 0) {
|
||||
warn("waitpid");
|
||||
} else if (WIFSIGNALED(x)) {
|
||||
warnx("pid %d: signal %d", pid, WTERMSIG(x));
|
||||
} else if (WEXITSTATUS(x) != 0) {
|
||||
warnx("pid %d: exit %d", pid, WEXITSTATUS(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually run the test.
|
||||
*/
|
||||
static
|
||||
void
|
||||
test(int nowait)
|
||||
{
|
||||
int pid0, pid1, pid2, pid3;
|
||||
int depth = 0;
|
||||
static void test(int nowait) {
|
||||
int pid0, pid1, pid2, pid3;
|
||||
int depth = 0;
|
||||
|
||||
/*
|
||||
* Caution: This generates processes geometrically.
|
||||
*
|
||||
* It is unrolled to encourage gcc to registerize the pids,
|
||||
* to prevent wait/exit problems if fork corrupts memory.
|
||||
*
|
||||
* Note: if the depth prints trigger and show that the depth
|
||||
* is too small, the most likely explanation is that the fork
|
||||
* child is returning from the write() inside putchar()
|
||||
* instead of from fork() and thus skipping the depth++. This
|
||||
* is a fairly common problem caused by races in the kernel
|
||||
* fork code.
|
||||
*/
|
||||
/*
|
||||
* Caution: This generates processes geometrically.
|
||||
*
|
||||
* It is unrolled to encourage gcc to registerize the pids,
|
||||
* to prevent wait/exit problems if fork corrupts memory.
|
||||
*
|
||||
* Note: if the depth prints trigger and show that the depth
|
||||
* is too small, the most likely explanation is that the fork
|
||||
* child is returning from the write() inside putchar()
|
||||
* instead of from fork() and thus skipping the depth++. This
|
||||
* is a fairly common problem caused by races in the kernel
|
||||
* fork code.
|
||||
*/
|
||||
|
||||
pid0 = dofork();
|
||||
depth++;
|
||||
putchar('A');
|
||||
if (depth != 1) {
|
||||
warnx("depth %d, should be 1", depth);
|
||||
}
|
||||
check();
|
||||
pid0 = dofork();
|
||||
depth++;
|
||||
putchar('A');
|
||||
if (depth != 1) {
|
||||
warnx("depth %d, should be 1", depth);
|
||||
}
|
||||
check();
|
||||
|
||||
pid1 = dofork();
|
||||
depth++;
|
||||
putchar('B');
|
||||
if (depth != 2) {
|
||||
warnx("depth %d, should be 2", depth);
|
||||
}
|
||||
check();
|
||||
pid1 = dofork();
|
||||
depth++;
|
||||
putchar('B');
|
||||
if (depth != 2) {
|
||||
warnx("depth %d, should be 2", depth);
|
||||
}
|
||||
check();
|
||||
|
||||
pid2 = dofork();
|
||||
depth++;
|
||||
putchar('C');
|
||||
if (depth != 3) {
|
||||
warnx("depth %d, should be 3", depth);
|
||||
}
|
||||
check();
|
||||
pid2 = dofork();
|
||||
depth++;
|
||||
putchar('C');
|
||||
if (depth != 3) {
|
||||
warnx("depth %d, should be 3", depth);
|
||||
}
|
||||
check();
|
||||
|
||||
pid3 = dofork();
|
||||
depth++;
|
||||
putchar('D');
|
||||
if (depth != 4) {
|
||||
warnx("depth %d, should be 4", depth);
|
||||
}
|
||||
check();
|
||||
pid3 = dofork();
|
||||
depth++;
|
||||
putchar('D');
|
||||
if (depth != 4) {
|
||||
warnx("depth %d, should be 4", depth);
|
||||
}
|
||||
check();
|
||||
|
||||
/*
|
||||
* These must be called in reverse order to avoid waiting
|
||||
* improperly.
|
||||
*/
|
||||
dowait(nowait, pid3);
|
||||
dowait(nowait, pid2);
|
||||
dowait(nowait, pid1);
|
||||
dowait(nowait, pid0);
|
||||
/*
|
||||
* These must be called in reverse order to avoid waiting
|
||||
* improperly.
|
||||
*/
|
||||
dowait(nowait, pid3);
|
||||
dowait(nowait, pid2);
|
||||
dowait(nowait, pid1);
|
||||
dowait(nowait, pid0);
|
||||
|
||||
putchar('\n');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
static const char expected[] =
|
||||
"|----------------------------|\n";
|
||||
int nowait=0;
|
||||
int main(int argc, char *argv[]) {
|
||||
static const char expected[] = "|----------------------------|\n";
|
||||
int nowait = 0;
|
||||
|
||||
if (argc==2 && !strcmp(argv[1], "-w")) {
|
||||
nowait=1;
|
||||
}
|
||||
else if (argc!=1 && argc!=0) {
|
||||
warnx("usage: forktest [-w]");
|
||||
return 1;
|
||||
}
|
||||
warnx("Starting. Expect this many:");
|
||||
write(STDERR_FILENO, expected, strlen(expected));
|
||||
if (argc == 2 && !strcmp(argv[1], "-w")) {
|
||||
nowait = 1;
|
||||
} else if (argc != 1 && argc != 0) {
|
||||
warnx("usage: forktest [-w]");
|
||||
return 1;
|
||||
}
|
||||
warnx("Starting. Expect this many:");
|
||||
write(STDERR_FILENO, expected, strlen(expected));
|
||||
|
||||
test(nowait);
|
||||
test(nowait);
|
||||
|
||||
warnx("Complete.");
|
||||
return 0;
|
||||
warnx("Complete.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,24 +28,22 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
int check_createfile(unsigned name);
|
||||
int check_openfile(unsigned name);
|
||||
void check_closefile(int handle, unsigned name);
|
||||
void check_write(int handle, unsigned name, unsigned code, unsigned seq,
|
||||
off_t pos, off_t len);
|
||||
off_t pos, off_t len);
|
||||
void check_truncate(int handle, unsigned name, off_t len);
|
||||
void check_mkdir(unsigned name);
|
||||
void check_rmdir(unsigned name);
|
||||
void check_unlink(unsigned name);
|
||||
void check_link(unsigned from, unsigned to);
|
||||
void check_rename(unsigned from, unsigned to);
|
||||
void check_renamexd(unsigned fromdir, unsigned from,
|
||||
unsigned todir, unsigned to);
|
||||
void check_renamexd(unsigned fromdir, unsigned from, unsigned todir,
|
||||
unsigned to);
|
||||
void check_chdir(unsigned name);
|
||||
void check_chdirup(void);
|
||||
void check_sync(void);
|
||||
|
||||
|
||||
void check_setup(void);
|
||||
void checkfs(void);
|
||||
|
||||
@@ -43,68 +43,51 @@
|
||||
static char databuf[DATA_MAXSIZE];
|
||||
static char readbuf[DATA_MAXSIZE];
|
||||
|
||||
static
|
||||
void
|
||||
prepdata(unsigned code, unsigned seq, char *buf, off_t len)
|
||||
{
|
||||
char smallbuf[32];
|
||||
char letter;
|
||||
size_t slen;
|
||||
static void prepdata(unsigned code, unsigned seq, char *buf, off_t len) {
|
||||
char smallbuf[32];
|
||||
char letter;
|
||||
size_t slen;
|
||||
|
||||
snprintf(smallbuf, sizeof(smallbuf), "%u@%u\n", seq, code);
|
||||
slen = strlen(smallbuf);
|
||||
snprintf(smallbuf, sizeof(smallbuf), "%u@%u\n", seq, code);
|
||||
slen = strlen(smallbuf);
|
||||
|
||||
while (len >= slen) {
|
||||
memcpy(buf, smallbuf, slen);
|
||||
buf += slen;
|
||||
len -= slen;
|
||||
}
|
||||
if (len > 1) {
|
||||
letter = 'A' + (code + seq) % 26;
|
||||
memset(buf, letter, len - 1);
|
||||
buf += len - 1;
|
||||
}
|
||||
if (len > 0) {
|
||||
*buf = '\n';
|
||||
}
|
||||
while (len >= slen) {
|
||||
memcpy(buf, smallbuf, slen);
|
||||
buf += slen;
|
||||
len -= slen;
|
||||
}
|
||||
if (len > 1) {
|
||||
letter = 'A' + (code + seq) % 26;
|
||||
memset(buf, letter, len - 1);
|
||||
buf += len - 1;
|
||||
}
|
||||
if (len > 0) {
|
||||
*buf = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
matches_at(size_t start, size_t len)
|
||||
{
|
||||
if (!memcmp(databuf + start, readbuf + start, len)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
static int matches_at(size_t start, size_t len) {
|
||||
if (!memcmp(databuf + start, readbuf + start, len)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
byte_at(size_t start, size_t len, unsigned char val)
|
||||
{
|
||||
size_t i;
|
||||
static int byte_at(size_t start, size_t len, unsigned char val) {
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
if ((unsigned char)readbuf[start + i] != val) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((unsigned char)readbuf[start + i] != val) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
zero_at(size_t start, size_t len)
|
||||
{
|
||||
return byte_at(start, len, 0);
|
||||
}
|
||||
static int zero_at(size_t start, size_t len) { return byte_at(start, len, 0); }
|
||||
|
||||
static
|
||||
int
|
||||
poison_at(size_t start, size_t len)
|
||||
{
|
||||
return byte_at(start, len, POISON_VAL);
|
||||
static int poison_at(size_t start, size_t len) {
|
||||
return byte_at(start, len, POISON_VAL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -119,109 +102,93 @@ poison_at(size_t start, size_t len)
|
||||
* CHECKSTART is the offset into the write region where we begin checking.
|
||||
* CHECKLEN is the length of the region we check.
|
||||
*/
|
||||
int
|
||||
data_matches(const char *namestr, off_t regionoffset,
|
||||
unsigned code, unsigned seq, off_t zerostart, off_t len,
|
||||
off_t checkstart, off_t checklen)
|
||||
{
|
||||
int ret;
|
||||
off_t where;
|
||||
size_t howmuch;
|
||||
off_t absend, slop;
|
||||
int data_matches(const char *namestr, off_t regionoffset, unsigned code,
|
||||
unsigned seq, off_t zerostart, off_t len, off_t checkstart,
|
||||
off_t checklen) {
|
||||
int ret;
|
||||
off_t where;
|
||||
size_t howmuch;
|
||||
off_t absend, slop;
|
||||
|
||||
assert(len <= DATA_MAXSIZE);
|
||||
assert(checklen > 0);
|
||||
assert(checklen <= len);
|
||||
assert(checkstart >= 0 && checkstart < len);
|
||||
assert(checkstart + checklen <= len);
|
||||
assert(zerostart >= 0);
|
||||
assert(zerostart <= len);
|
||||
assert(len <= DATA_MAXSIZE);
|
||||
assert(checklen > 0);
|
||||
assert(checklen <= len);
|
||||
assert(checkstart >= 0 && checkstart < len);
|
||||
assert(checkstart + checklen <= len);
|
||||
assert(zerostart >= 0);
|
||||
assert(zerostart <= len);
|
||||
|
||||
prepdata(code, seq, databuf, len);
|
||||
prepdata(code, seq, databuf, len);
|
||||
|
||||
ret = 1;
|
||||
while (checklen > 0) {
|
||||
/* check one block at a time */
|
||||
where = checkstart;
|
||||
howmuch = BLOCKSIZE;
|
||||
/* no more than is left to do */
|
||||
if (howmuch > checklen) {
|
||||
howmuch = checklen;
|
||||
}
|
||||
/* if we stick over a block boundary, stop there */
|
||||
absend = regionoffset + where + howmuch;
|
||||
slop = absend % BLOCKSIZE;
|
||||
if (slop != 0 && slop < howmuch) {
|
||||
howmuch -= slop;
|
||||
}
|
||||
/* if we go past the zerostart point, stop there */
|
||||
if (where < zerostart && where + howmuch > zerostart) {
|
||||
howmuch = zerostart - where;
|
||||
}
|
||||
assert(howmuch > 0);
|
||||
ret = 1;
|
||||
while (checklen > 0) {
|
||||
/* check one block at a time */
|
||||
where = checkstart;
|
||||
howmuch = BLOCKSIZE;
|
||||
/* no more than is left to do */
|
||||
if (howmuch > checklen) {
|
||||
howmuch = checklen;
|
||||
}
|
||||
/* if we stick over a block boundary, stop there */
|
||||
absend = regionoffset + where + howmuch;
|
||||
slop = absend % BLOCKSIZE;
|
||||
if (slop != 0 && slop < howmuch) {
|
||||
howmuch -= slop;
|
||||
}
|
||||
/* if we go past the zerostart point, stop there */
|
||||
if (where < zerostart && where + howmuch > zerostart) {
|
||||
howmuch = zerostart - where;
|
||||
}
|
||||
assert(howmuch > 0);
|
||||
|
||||
if (matches_at(where, howmuch)) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (zero_at(where, howmuch)) {
|
||||
if (where >= zerostart) {
|
||||
printf("WARNING: file %s range %lld-%lld is "
|
||||
"zeroed\n",
|
||||
namestr, regionoffset + where,
|
||||
regionoffset + where + howmuch);
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
else if (poison_at(where, howmuch)) {
|
||||
if (where >= zerostart) {
|
||||
printf("ERROR: file %s range %lld-%lld is "
|
||||
"poisoned\n",
|
||||
namestr, regionoffset + where,
|
||||
regionoffset + where + howmuch);
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
}
|
||||
if (matches_at(where, howmuch)) {
|
||||
/* nothing */
|
||||
} else if (zero_at(where, howmuch)) {
|
||||
if (where >= zerostart) {
|
||||
printf("WARNING: file %s range %lld-%lld is "
|
||||
"zeroed\n",
|
||||
namestr, regionoffset + where, regionoffset + where + howmuch);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
} else if (poison_at(where, howmuch)) {
|
||||
if (where >= zerostart) {
|
||||
printf("ERROR: file %s range %lld-%lld is "
|
||||
"poisoned\n",
|
||||
namestr, regionoffset + where, regionoffset + where + howmuch);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
checkstart += howmuch;
|
||||
checklen -= howmuch;
|
||||
}
|
||||
return ret;
|
||||
checkstart += howmuch;
|
||||
checklen -= howmuch;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
data_check(const char *namestr, off_t regionoffset,
|
||||
unsigned code, unsigned seq, off_t zerostart, off_t len,
|
||||
off_t checkstart, off_t checklen)
|
||||
{
|
||||
assert(zerostart >= 0);
|
||||
assert(zerostart <= len);
|
||||
void data_check(const char *namestr, off_t regionoffset, unsigned code,
|
||||
unsigned seq, off_t zerostart, off_t len, off_t checkstart,
|
||||
off_t checklen) {
|
||||
assert(zerostart >= 0);
|
||||
assert(zerostart <= len);
|
||||
|
||||
if (!data_matches(namestr, regionoffset,
|
||||
code, seq, zerostart, len, checkstart, checklen)) {
|
||||
printf("ERROR: file %s range %lld-%lld contains garbage\n",
|
||||
namestr, regionoffset + checkstart,
|
||||
regionoffset + checkstart + checklen);
|
||||
}
|
||||
if (!data_matches(namestr, regionoffset, code, seq, zerostart, len,
|
||||
checkstart, checklen)) {
|
||||
printf("ERROR: file %s range %lld-%lld contains garbage\n", namestr,
|
||||
regionoffset + checkstart, regionoffset + checkstart + checklen);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
data_map(unsigned code, unsigned seq, off_t len)
|
||||
{
|
||||
assert(len <= DATA_MAXSIZE);
|
||||
prepdata(code, seq, databuf, len);
|
||||
return databuf;
|
||||
void *data_map(unsigned code, unsigned seq, off_t len) {
|
||||
assert(len <= DATA_MAXSIZE);
|
||||
prepdata(code, seq, databuf, len);
|
||||
return databuf;
|
||||
}
|
||||
|
||||
void *
|
||||
data_mapreadbuf(off_t len)
|
||||
{
|
||||
assert(len <= DATA_MAXSIZE);
|
||||
return readbuf;
|
||||
void *data_mapreadbuf(off_t len) {
|
||||
assert(len <= DATA_MAXSIZE);
|
||||
return readbuf;
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
|
||||
void *data_map(unsigned code, unsigned seq, off_t len);
|
||||
void *data_mapreadbuf(off_t len);
|
||||
int data_matches(const char *namestr, off_t regionoffset,
|
||||
unsigned code, unsigned seq, off_t zerostart, off_t len,
|
||||
off_t checkstart, off_t checklen);
|
||||
void data_check(const char *namestr, off_t regionoffset,
|
||||
unsigned code, unsigned seq, off_t zerostart, off_t len,
|
||||
off_t checkstart, off_t checklen);
|
||||
int data_matches(const char *namestr, off_t regionoffset, unsigned code,
|
||||
unsigned seq, off_t zerostart, off_t len, off_t checkstart,
|
||||
off_t checklen);
|
||||
void data_check(const char *namestr, off_t regionoffset, unsigned code,
|
||||
unsigned seq, off_t zerostart, off_t len, off_t checkstart,
|
||||
off_t checklen);
|
||||
|
||||
#define DATA_MAXSIZE 65536
|
||||
#define POISON_VAL 0xa9
|
||||
|
||||
@@ -39,213 +39,180 @@
|
||||
#include "name.h"
|
||||
#include "do.h"
|
||||
|
||||
int
|
||||
do_opendir(unsigned name)
|
||||
{
|
||||
const char *namestr;
|
||||
int fd;
|
||||
int do_opendir(unsigned name) {
|
||||
const char *namestr;
|
||||
int fd;
|
||||
|
||||
namestr = name_get(name);
|
||||
fd = open(namestr, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: opendir", namestr);
|
||||
}
|
||||
return fd;
|
||||
namestr = name_get(name);
|
||||
fd = open(namestr, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: opendir", namestr);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
do_closedir(int fd, unsigned name)
|
||||
{
|
||||
if (close(fd)) {
|
||||
warn("%s: closedir", name_get(name));
|
||||
}
|
||||
void do_closedir(int fd, unsigned name) {
|
||||
if (close(fd)) {
|
||||
warn("%s: closedir", name_get(name));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
do_createfile(unsigned name)
|
||||
{
|
||||
const char *namestr;
|
||||
int fd;
|
||||
int do_createfile(unsigned name) {
|
||||
const char *namestr;
|
||||
int fd;
|
||||
|
||||
namestr = name_get(name);
|
||||
fd = open(namestr, O_WRONLY|O_CREAT|O_EXCL, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", namestr);
|
||||
}
|
||||
printf("create %s\n", namestr);
|
||||
return fd;
|
||||
namestr = name_get(name);
|
||||
fd = open(namestr, O_WRONLY | O_CREAT | O_EXCL, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", namestr);
|
||||
}
|
||||
printf("create %s\n", namestr);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
do_openfile(unsigned name, int dotrunc)
|
||||
{
|
||||
const char *namestr;
|
||||
int fd;
|
||||
int do_openfile(unsigned name, int dotrunc) {
|
||||
const char *namestr;
|
||||
int fd;
|
||||
|
||||
namestr = name_get(name);
|
||||
fd = open(namestr, O_WRONLY | (dotrunc ? O_TRUNC : 0), 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open", namestr);
|
||||
}
|
||||
return fd;
|
||||
namestr = name_get(name);
|
||||
fd = open(namestr, O_WRONLY | (dotrunc ? O_TRUNC : 0), 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: open", namestr);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
do_closefile(int fd, unsigned name)
|
||||
{
|
||||
if (close(fd)) {
|
||||
warn("%s: close", name_get(name));
|
||||
}
|
||||
void do_closefile(int fd, unsigned name) {
|
||||
if (close(fd)) {
|
||||
warn("%s: close", name_get(name));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
do_write(int fd, unsigned name, unsigned code, unsigned seq,
|
||||
off_t pos, off_t len)
|
||||
{
|
||||
off_t done = 0;
|
||||
ssize_t ret;
|
||||
char *buf;
|
||||
const char *namestr;
|
||||
void do_write(int fd, unsigned name, unsigned code, unsigned seq, off_t pos,
|
||||
off_t len) {
|
||||
off_t done = 0;
|
||||
ssize_t ret;
|
||||
char *buf;
|
||||
const char *namestr;
|
||||
|
||||
namestr = name_get(name);
|
||||
buf = data_map(code, seq, len);
|
||||
if (lseek(fd, pos, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek to %lld", name_get(name), pos);
|
||||
}
|
||||
namestr = name_get(name);
|
||||
buf = data_map(code, seq, len);
|
||||
if (lseek(fd, pos, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek to %lld", name_get(name), pos);
|
||||
}
|
||||
|
||||
while (done < len) {
|
||||
ret = write(fd, buf + done, len - done);
|
||||
if (ret == -1) {
|
||||
err(1, "%s: write %lld at %lld", name_get(name),
|
||||
len, pos);
|
||||
}
|
||||
done += ret;
|
||||
}
|
||||
while (done < len) {
|
||||
ret = write(fd, buf + done, len - done);
|
||||
if (ret == -1) {
|
||||
err(1, "%s: write %lld at %lld", name_get(name), len, pos);
|
||||
}
|
||||
done += ret;
|
||||
}
|
||||
|
||||
printf("write %s: %lld at %lld\n", namestr, len, pos);
|
||||
printf("write %s: %lld at %lld\n", namestr, len, pos);
|
||||
}
|
||||
|
||||
void
|
||||
do_truncate(int fd, unsigned name, off_t len)
|
||||
{
|
||||
const char *namestr;
|
||||
void do_truncate(int fd, unsigned name, off_t len) {
|
||||
const char *namestr;
|
||||
|
||||
namestr = name_get(name);
|
||||
if (ftruncate(fd, len) == -1) {
|
||||
err(1, "%s: truncate to %lld", namestr, len);
|
||||
}
|
||||
printf("truncate %s: to %lld\n", namestr, len);
|
||||
namestr = name_get(name);
|
||||
if (ftruncate(fd, len) == -1) {
|
||||
err(1, "%s: truncate to %lld", namestr, len);
|
||||
}
|
||||
printf("truncate %s: to %lld\n", namestr, len);
|
||||
}
|
||||
|
||||
void
|
||||
do_mkdir(unsigned name)
|
||||
{
|
||||
const char *namestr;
|
||||
void do_mkdir(unsigned name) {
|
||||
const char *namestr;
|
||||
|
||||
namestr = name_get(name);
|
||||
if (mkdir(namestr, 0775) == -1) {
|
||||
err(1, "%s: mkdir", namestr);
|
||||
}
|
||||
printf("mkdir %s\n", namestr);
|
||||
namestr = name_get(name);
|
||||
if (mkdir(namestr, 0775) == -1) {
|
||||
err(1, "%s: mkdir", namestr);
|
||||
}
|
||||
printf("mkdir %s\n", namestr);
|
||||
}
|
||||
|
||||
void
|
||||
do_rmdir(unsigned name)
|
||||
{
|
||||
const char *namestr;
|
||||
void do_rmdir(unsigned name) {
|
||||
const char *namestr;
|
||||
|
||||
namestr = name_get(name);
|
||||
if (rmdir(namestr) == -1) {
|
||||
err(1, "%s: rmdir", namestr);
|
||||
}
|
||||
printf("rmdir %s\n", namestr);
|
||||
namestr = name_get(name);
|
||||
if (rmdir(namestr) == -1) {
|
||||
err(1, "%s: rmdir", namestr);
|
||||
}
|
||||
printf("rmdir %s\n", namestr);
|
||||
}
|
||||
|
||||
void
|
||||
do_unlink(unsigned name)
|
||||
{
|
||||
const char *namestr;
|
||||
void do_unlink(unsigned name) {
|
||||
const char *namestr;
|
||||
|
||||
namestr = name_get(name);
|
||||
if (remove(namestr) == -1) {
|
||||
err(1, "%s: remove", namestr);
|
||||
}
|
||||
printf("remove %s\n", namestr);
|
||||
namestr = name_get(name);
|
||||
if (remove(namestr) == -1) {
|
||||
err(1, "%s: remove", namestr);
|
||||
}
|
||||
printf("remove %s\n", namestr);
|
||||
}
|
||||
|
||||
void
|
||||
do_link(unsigned from, unsigned to)
|
||||
{
|
||||
const char *fromstr, *tostr;
|
||||
void do_link(unsigned from, unsigned to) {
|
||||
const char *fromstr, *tostr;
|
||||
|
||||
fromstr = name_get(from);
|
||||
tostr = name_get(to);
|
||||
if (link(fromstr, tostr) == -1) {
|
||||
err(1, "link %s to %s", fromstr, tostr);
|
||||
}
|
||||
printf("link %s %s\n", fromstr, tostr);
|
||||
fromstr = name_get(from);
|
||||
tostr = name_get(to);
|
||||
if (link(fromstr, tostr) == -1) {
|
||||
err(1, "link %s to %s", fromstr, tostr);
|
||||
}
|
||||
printf("link %s %s\n", fromstr, tostr);
|
||||
}
|
||||
|
||||
void
|
||||
do_rename(unsigned from, unsigned to)
|
||||
{
|
||||
const char *fromstr, *tostr;
|
||||
void do_rename(unsigned from, unsigned to) {
|
||||
const char *fromstr, *tostr;
|
||||
|
||||
fromstr = name_get(from);
|
||||
tostr = name_get(to);
|
||||
if (rename(fromstr, tostr) == -1) {
|
||||
err(1, "rename %s to %s", fromstr, tostr);
|
||||
}
|
||||
printf("rename %s %s\n", fromstr, tostr);
|
||||
fromstr = name_get(from);
|
||||
tostr = name_get(to);
|
||||
if (rename(fromstr, tostr) == -1) {
|
||||
err(1, "rename %s to %s", fromstr, tostr);
|
||||
}
|
||||
printf("rename %s %s\n", fromstr, tostr);
|
||||
}
|
||||
|
||||
void
|
||||
do_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to)
|
||||
{
|
||||
char frombuf[64];
|
||||
char tobuf[64];
|
||||
void do_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to) {
|
||||
char frombuf[64];
|
||||
char tobuf[64];
|
||||
|
||||
strcpy(frombuf, name_get(fromdir));
|
||||
strcat(frombuf, "/");
|
||||
strcat(frombuf, name_get(from));
|
||||
strcpy(frombuf, name_get(fromdir));
|
||||
strcat(frombuf, "/");
|
||||
strcat(frombuf, name_get(from));
|
||||
|
||||
strcpy(tobuf, name_get(todir));
|
||||
strcat(tobuf, "/");
|
||||
strcat(tobuf, name_get(to));
|
||||
strcpy(tobuf, name_get(todir));
|
||||
strcat(tobuf, "/");
|
||||
strcat(tobuf, name_get(to));
|
||||
|
||||
if (rename(frombuf, tobuf) == -1) {
|
||||
err(1, "rename %s to %s", frombuf, tobuf);
|
||||
}
|
||||
printf("rename %s %s\n", frombuf, tobuf);
|
||||
if (rename(frombuf, tobuf) == -1) {
|
||||
err(1, "rename %s to %s", frombuf, tobuf);
|
||||
}
|
||||
printf("rename %s %s\n", frombuf, tobuf);
|
||||
}
|
||||
|
||||
void
|
||||
do_chdir(unsigned name)
|
||||
{
|
||||
const char *namestr;
|
||||
void do_chdir(unsigned name) {
|
||||
const char *namestr;
|
||||
|
||||
namestr = name_get(name);
|
||||
if (chdir(namestr) == -1) {
|
||||
err(1, "chdir: %s", namestr);
|
||||
}
|
||||
printf("chdir %s\n", namestr);
|
||||
namestr = name_get(name);
|
||||
if (chdir(namestr) == -1) {
|
||||
err(1, "chdir: %s", namestr);
|
||||
}
|
||||
printf("chdir %s\n", namestr);
|
||||
}
|
||||
|
||||
void
|
||||
do_chdirup(void)
|
||||
{
|
||||
if (chdir("..") == -1) {
|
||||
err(1, "chdir: ..");
|
||||
}
|
||||
printf("chdir ..\n");
|
||||
void do_chdirup(void) {
|
||||
if (chdir("..") == -1) {
|
||||
err(1, "chdir: ..");
|
||||
}
|
||||
printf("chdir ..\n");
|
||||
}
|
||||
|
||||
void
|
||||
do_sync(void)
|
||||
{
|
||||
if (sync()) {
|
||||
warn("sync");
|
||||
}
|
||||
printf("sync\n");
|
||||
printf("----------------------------------------\n");
|
||||
void do_sync(void) {
|
||||
if (sync()) {
|
||||
warn("sync");
|
||||
}
|
||||
printf("sync\n");
|
||||
printf("----------------------------------------\n");
|
||||
}
|
||||
|
||||
@@ -28,14 +28,13 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
int do_opendir(unsigned name);
|
||||
void do_closedir(int handle, unsigned name);
|
||||
int do_createfile(unsigned name);
|
||||
int do_openfile(unsigned name, int dotrunc);
|
||||
void do_closefile(int handle, unsigned name);
|
||||
void do_write(int handle, unsigned name, unsigned code, unsigned seq,
|
||||
off_t pos, off_t len);
|
||||
void do_write(int handle, unsigned name, unsigned code, unsigned seq, off_t pos,
|
||||
off_t len);
|
||||
void do_truncate(int handle, unsigned name, off_t len);
|
||||
void do_mkdir(unsigned name);
|
||||
void do_rmdir(unsigned name);
|
||||
|
||||
@@ -37,160 +37,148 @@
|
||||
#include "main.h"
|
||||
|
||||
struct workload {
|
||||
const char *name;
|
||||
const char *argname;
|
||||
union {
|
||||
void (*witharg)(const char *);
|
||||
void (*noarg)(void);
|
||||
} run;
|
||||
const char *name;
|
||||
const char *argname;
|
||||
union {
|
||||
void (*witharg)(const char *);
|
||||
void (*noarg)(void);
|
||||
} run;
|
||||
};
|
||||
|
||||
#define WL(n) { .name = #n, .argname = NULL, .run.noarg = wl_##n }
|
||||
#define WLA(n,a) { .name = #n, .argname = #a, .run.witharg = wl_##n }
|
||||
#define WL(n) {.name = #n, .argname = NULL, .run.noarg = wl_##n}
|
||||
#define WLA(n, a) {.name = #n, .argname = #a, .run.witharg = wl_##n}
|
||||
|
||||
static const struct workload workloads[] = {
|
||||
WLA(createwrite, size),
|
||||
WLA(rewrite, size),
|
||||
WLA(randupdate, size),
|
||||
WLA(truncwrite, size),
|
||||
WLA(makehole, size),
|
||||
WLA(fillhole, size),
|
||||
WLA(truncfill, size),
|
||||
WLA(append, size),
|
||||
WLA(trunczero, size),
|
||||
WLA(trunconeblock, size),
|
||||
WLA(truncsmallersize, size),
|
||||
WLA(trunclargersize, size),
|
||||
WLA(appendandtrunczero, size),
|
||||
WLA(appendandtruncpartly, size),
|
||||
WL(mkfile),
|
||||
WL(mkdir),
|
||||
WL(mkmanyfile),
|
||||
WL(mkmanydir),
|
||||
WL(mktree),
|
||||
WLA(mkrandtree, seed),
|
||||
WL(rmfile),
|
||||
WL(rmdir),
|
||||
WL(rmfiledelayed),
|
||||
WL(rmfiledelayedappend),
|
||||
WL(rmdirdelayed),
|
||||
WL(rmmanyfile),
|
||||
WL(rmmanyfiledelayed),
|
||||
WL(rmmanyfiledelayedandappend),
|
||||
WL(rmmanydir),
|
||||
WL(rmmanydirdelayed),
|
||||
WL(rmtree),
|
||||
WLA(rmrandtree, seed),
|
||||
WL(linkfile),
|
||||
WL(linkmanyfile),
|
||||
WL(unlinkfile),
|
||||
WL(unlinkmanyfile),
|
||||
WL(linkunlinkfile),
|
||||
WL(renamefile),
|
||||
WL(renamedir),
|
||||
WL(renamesubtree),
|
||||
WL(renamexdfile),
|
||||
WL(renamexddir),
|
||||
WL(renamexdsubtree),
|
||||
WL(renamemanyfile),
|
||||
WL(renamemanydir),
|
||||
WL(renamemanysubtree),
|
||||
WL(copyandrename),
|
||||
WL(untar),
|
||||
WL(compile),
|
||||
WL(cvsupdate),
|
||||
WLA(writefileseq, seed),
|
||||
WLA(writetruncseq, seed),
|
||||
WLA(mkrmseq, seed),
|
||||
WLA(linkunlinkseq, seed),
|
||||
WLA(renameseq, seed),
|
||||
WLA(diropseq, seed),
|
||||
WLA(genseq, seed),
|
||||
WLA(createwrite, size),
|
||||
WLA(rewrite, size),
|
||||
WLA(randupdate, size),
|
||||
WLA(truncwrite, size),
|
||||
WLA(makehole, size),
|
||||
WLA(fillhole, size),
|
||||
WLA(truncfill, size),
|
||||
WLA(append, size),
|
||||
WLA(trunczero, size),
|
||||
WLA(trunconeblock, size),
|
||||
WLA(truncsmallersize, size),
|
||||
WLA(trunclargersize, size),
|
||||
WLA(appendandtrunczero, size),
|
||||
WLA(appendandtruncpartly, size),
|
||||
WL(mkfile),
|
||||
WL(mkdir),
|
||||
WL(mkmanyfile),
|
||||
WL(mkmanydir),
|
||||
WL(mktree),
|
||||
WLA(mkrandtree, seed),
|
||||
WL(rmfile),
|
||||
WL(rmdir),
|
||||
WL(rmfiledelayed),
|
||||
WL(rmfiledelayedappend),
|
||||
WL(rmdirdelayed),
|
||||
WL(rmmanyfile),
|
||||
WL(rmmanyfiledelayed),
|
||||
WL(rmmanyfiledelayedandappend),
|
||||
WL(rmmanydir),
|
||||
WL(rmmanydirdelayed),
|
||||
WL(rmtree),
|
||||
WLA(rmrandtree, seed),
|
||||
WL(linkfile),
|
||||
WL(linkmanyfile),
|
||||
WL(unlinkfile),
|
||||
WL(unlinkmanyfile),
|
||||
WL(linkunlinkfile),
|
||||
WL(renamefile),
|
||||
WL(renamedir),
|
||||
WL(renamesubtree),
|
||||
WL(renamexdfile),
|
||||
WL(renamexddir),
|
||||
WL(renamexdsubtree),
|
||||
WL(renamemanyfile),
|
||||
WL(renamemanydir),
|
||||
WL(renamemanysubtree),
|
||||
WL(copyandrename),
|
||||
WL(untar),
|
||||
WL(compile),
|
||||
WL(cvsupdate),
|
||||
WLA(writefileseq, seed),
|
||||
WLA(writetruncseq, seed),
|
||||
WLA(mkrmseq, seed),
|
||||
WLA(linkunlinkseq, seed),
|
||||
WLA(renameseq, seed),
|
||||
WLA(diropseq, seed),
|
||||
WLA(genseq, seed),
|
||||
};
|
||||
static const unsigned numworkloads = sizeof(workloads) / sizeof(workloads[0]);
|
||||
|
||||
#undef WL
|
||||
#undef WLA
|
||||
|
||||
static
|
||||
const struct workload *
|
||||
findworkload(const char *name)
|
||||
{
|
||||
unsigned i;
|
||||
static const struct workload *findworkload(const char *name) {
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<numworkloads; i++) {
|
||||
if (!strcmp(workloads[i].name, name)) {
|
||||
return &workloads[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
for (i = 0; i < numworkloads; i++) {
|
||||
if (!strcmp(workloads[i].name, name)) {
|
||||
return &workloads[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
printworkloads(void)
|
||||
{
|
||||
unsigned i;
|
||||
static void printworkloads(void) {
|
||||
unsigned i;
|
||||
|
||||
printf("Supported workloads:\n");
|
||||
for (i=0; i<numworkloads; i++) {
|
||||
printf(" %s", workloads[i].name);
|
||||
if (workloads[i].argname) {
|
||||
printf(" %s", workloads[i].argname);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("Supported workloads:\n");
|
||||
for (i = 0; i < numworkloads; i++) {
|
||||
printf(" %s", workloads[i].name);
|
||||
if (workloads[i].argname) {
|
||||
printf(" %s", workloads[i].argname);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *workloadname;
|
||||
const struct workload *workload;
|
||||
int checkmode = 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *workloadname;
|
||||
const struct workload *workload;
|
||||
int checkmode = 0;
|
||||
|
||||
if (argc == 2 && !strcmp(argv[1], "list")) {
|
||||
printworkloads();
|
||||
exit(0);
|
||||
}
|
||||
if (argc == 2 && !strcmp(argv[1], "list")) {
|
||||
printworkloads();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc < 3) {
|
||||
warnx("Usage: %s do|check workload [arg]", argv[0]);
|
||||
warnx("Use \"list\" for a list of workloads");
|
||||
exit(1);
|
||||
}
|
||||
if (argc < 3) {
|
||||
warnx("Usage: %s do|check workload [arg]", argv[0]);
|
||||
warnx("Use \"list\" for a list of workloads");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "do")) {
|
||||
checkmode = 0;
|
||||
}
|
||||
else if (!strcmp(argv[1], "check")) {
|
||||
checkmode = 1;
|
||||
}
|
||||
else {
|
||||
errx(1, "Action must be \"do\" or \"check\"");
|
||||
}
|
||||
if (!strcmp(argv[1], "do")) {
|
||||
checkmode = 0;
|
||||
} else if (!strcmp(argv[1], "check")) {
|
||||
checkmode = 1;
|
||||
} else {
|
||||
errx(1, "Action must be \"do\" or \"check\"");
|
||||
}
|
||||
|
||||
workloadname = argv[2];
|
||||
workload = findworkload(workloadname);
|
||||
if (workload == NULL) {
|
||||
errx(1, "Unknown workload %s\n", workloadname);
|
||||
printworkloads();
|
||||
exit(1);
|
||||
}
|
||||
setcheckmode(checkmode);
|
||||
if (workload->argname) {
|
||||
if (argc != 4) {
|
||||
errx(1, "%s requires argument %s\n",
|
||||
workloadname, workload->argname);
|
||||
}
|
||||
workload->run.witharg(argv[3]);
|
||||
}
|
||||
else {
|
||||
if (argc != 3) {
|
||||
errx(1, "Stray argument for workload %s",workloadname);
|
||||
}
|
||||
workload->run.noarg();
|
||||
}
|
||||
complete();
|
||||
return 0;
|
||||
workloadname = argv[2];
|
||||
workload = findworkload(workloadname);
|
||||
if (workload == NULL) {
|
||||
errx(1, "Unknown workload %s\n", workloadname);
|
||||
printworkloads();
|
||||
exit(1);
|
||||
}
|
||||
setcheckmode(checkmode);
|
||||
if (workload->argname) {
|
||||
if (argc != 4) {
|
||||
errx(1, "%s requires argument %s\n", workloadname, workload->argname);
|
||||
}
|
||||
workload->run.witharg(argv[3]);
|
||||
} else {
|
||||
if (argc != 3) {
|
||||
errx(1, "Stray argument for workload %s", workloadname);
|
||||
}
|
||||
workload->run.noarg();
|
||||
}
|
||||
complete();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,57 +37,28 @@
|
||||
#define MAXNAMES 32
|
||||
|
||||
static const char *const names[MAXNAMES] = {
|
||||
"allspice",
|
||||
"anise",
|
||||
"basil",
|
||||
"cardamom",
|
||||
"cayenne",
|
||||
"cilantro",
|
||||
"cinnamon",
|
||||
"cloves",
|
||||
"coriander",
|
||||
"cumin",
|
||||
"dill",
|
||||
"fennel",
|
||||
"fenugreek",
|
||||
"galangal",
|
||||
"ginger",
|
||||
"horseradish",
|
||||
"lemongrass",
|
||||
"licorice",
|
||||
"mace",
|
||||
"marjoram",
|
||||
"mustard",
|
||||
"nutmeg",
|
||||
"oregano",
|
||||
"parsley",
|
||||
"paprika",
|
||||
"pepper",
|
||||
"saffron",
|
||||
"sage",
|
||||
"rosemary",
|
||||
"thyme",
|
||||
"turmeric",
|
||||
"wasabi",
|
||||
"allspice", "anise", "basil", "cardamom", "cayenne",
|
||||
"cilantro", "cinnamon", "cloves", "coriander", "cumin",
|
||||
"dill", "fennel", "fenugreek", "galangal", "ginger",
|
||||
"horseradish", "lemongrass", "licorice", "mace", "marjoram",
|
||||
"mustard", "nutmeg", "oregano", "parsley", "paprika",
|
||||
"pepper", "saffron", "sage", "rosemary", "thyme",
|
||||
"turmeric", "wasabi",
|
||||
};
|
||||
|
||||
const char *
|
||||
name_get(unsigned name)
|
||||
{
|
||||
assert(name < MAXNAMES);
|
||||
return names[name];
|
||||
const char *name_get(unsigned name) {
|
||||
assert(name < MAXNAMES);
|
||||
return names[name];
|
||||
}
|
||||
|
||||
unsigned
|
||||
name_find(const char *namestr)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned name_find(const char *namestr) {
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<MAXNAMES; i++) {
|
||||
if (!strcmp(namestr, names[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
errx(1, "Encountered unknown/unexpected name %s", namestr);
|
||||
return 0;
|
||||
for (i = 0; i < MAXNAMES; i++) {
|
||||
if (!strcmp(namestr, names[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
errx(1, "Encountered unknown/unexpected name %s", namestr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,5 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
const char *name_get(unsigned name);
|
||||
unsigned name_find(const char *namestr);
|
||||
|
||||
@@ -41,26 +41,24 @@
|
||||
#include "main.h"
|
||||
|
||||
struct file {
|
||||
unsigned name;
|
||||
unsigned testcode;
|
||||
unsigned seq;
|
||||
int handle;
|
||||
unsigned name;
|
||||
unsigned testcode;
|
||||
unsigned seq;
|
||||
int handle;
|
||||
};
|
||||
|
||||
struct dir {
|
||||
unsigned name;
|
||||
int handle;
|
||||
unsigned name;
|
||||
int handle;
|
||||
};
|
||||
|
||||
static int checkmode;
|
||||
|
||||
void
|
||||
setcheckmode(int mode)
|
||||
{
|
||||
checkmode = mode;
|
||||
if (checkmode) {
|
||||
check_setup();
|
||||
}
|
||||
void setcheckmode(int mode) {
|
||||
checkmode = mode;
|
||||
if (checkmode) {
|
||||
check_setup();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -69,33 +67,27 @@ setcheckmode(int mode)
|
||||
#define MAXDIRS 32
|
||||
DECLPOOL(dir, MAXDIRS);
|
||||
|
||||
struct dir *
|
||||
op_opendir(unsigned name)
|
||||
{
|
||||
struct dir *ret;
|
||||
struct dir *op_opendir(unsigned name) {
|
||||
struct dir *ret;
|
||||
|
||||
ret = POOLALLOC(dir);
|
||||
ret->name = name;
|
||||
if (checkmode) {
|
||||
ret->handle = -1;
|
||||
}
|
||||
else {
|
||||
ret->handle = do_opendir(name);
|
||||
}
|
||||
return ret;
|
||||
ret = POOLALLOC(dir);
|
||||
ret->name = name;
|
||||
if (checkmode) {
|
||||
ret->handle = -1;
|
||||
} else {
|
||||
ret->handle = do_opendir(name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
op_closedir(struct dir *d)
|
||||
{
|
||||
if (checkmode) {
|
||||
/* nothing */
|
||||
(void)d;
|
||||
}
|
||||
else {
|
||||
do_closedir(d->handle, d->name);
|
||||
}
|
||||
POOLFREE(dir, d);
|
||||
void op_closedir(struct dir *d) {
|
||||
if (checkmode) {
|
||||
/* nothing */
|
||||
(void)d;
|
||||
} else {
|
||||
do_closedir(d->handle, d->name);
|
||||
}
|
||||
POOLFREE(dir, d);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -104,212 +96,166 @@ op_closedir(struct dir *d)
|
||||
#define MAXFILES 32
|
||||
DECLPOOL(file, MAXFILES);
|
||||
|
||||
struct file *
|
||||
op_open(unsigned testcode, unsigned name, unsigned openflags)
|
||||
{
|
||||
struct file *ret;
|
||||
int dotrunc;
|
||||
struct file *op_open(unsigned testcode, unsigned name, unsigned openflags) {
|
||||
struct file *ret;
|
||||
int dotrunc;
|
||||
|
||||
if (openflags == O_TRUNC) {
|
||||
openflags = 0;
|
||||
dotrunc = 1;
|
||||
}
|
||||
else {
|
||||
dotrunc = 0;
|
||||
}
|
||||
if (openflags == O_TRUNC) {
|
||||
openflags = 0;
|
||||
dotrunc = 1;
|
||||
} else {
|
||||
dotrunc = 0;
|
||||
}
|
||||
|
||||
assert(openflags == 0 || openflags == (O_CREAT|O_EXCL));
|
||||
assert(openflags == 0 || openflags == (O_CREAT | O_EXCL));
|
||||
|
||||
ret = POOLALLOC(file);
|
||||
ret->name = name;
|
||||
ret->testcode = testcode;
|
||||
ret->seq = 0;
|
||||
if (checkmode) {
|
||||
if (openflags) {
|
||||
ret->handle = check_createfile(name);
|
||||
}
|
||||
else {
|
||||
ret->handle = check_openfile(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (openflags) {
|
||||
assert(dotrunc == 0);
|
||||
ret->handle = do_createfile(name);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* XXX: as of 2013 OS/161 doesn't provide a
|
||||
* truncate call - neither truncate() nor
|
||||
* ftruncate()! You can only O_TRUNC. Oops...
|
||||
*/
|
||||
ret->handle = do_openfile(name, dotrunc);
|
||||
dotrunc = 0;
|
||||
}
|
||||
}
|
||||
if (dotrunc) {
|
||||
op_truncate(ret, 0);
|
||||
}
|
||||
return ret;
|
||||
ret = POOLALLOC(file);
|
||||
ret->name = name;
|
||||
ret->testcode = testcode;
|
||||
ret->seq = 0;
|
||||
if (checkmode) {
|
||||
if (openflags) {
|
||||
ret->handle = check_createfile(name);
|
||||
} else {
|
||||
ret->handle = check_openfile(name);
|
||||
}
|
||||
} else {
|
||||
if (openflags) {
|
||||
assert(dotrunc == 0);
|
||||
ret->handle = do_createfile(name);
|
||||
} else {
|
||||
/*
|
||||
* XXX: as of 2013 OS/161 doesn't provide a
|
||||
* truncate call - neither truncate() nor
|
||||
* ftruncate()! You can only O_TRUNC. Oops...
|
||||
*/
|
||||
ret->handle = do_openfile(name, dotrunc);
|
||||
dotrunc = 0;
|
||||
}
|
||||
}
|
||||
if (dotrunc) {
|
||||
op_truncate(ret, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
op_close(struct file *f)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_closefile(f->handle, f->name);
|
||||
}
|
||||
else {
|
||||
do_closefile(f->handle, f->name);
|
||||
}
|
||||
POOLFREE(file, f);
|
||||
void op_close(struct file *f) {
|
||||
if (checkmode) {
|
||||
check_closefile(f->handle, f->name);
|
||||
} else {
|
||||
do_closefile(f->handle, f->name);
|
||||
}
|
||||
POOLFREE(file, f);
|
||||
}
|
||||
|
||||
void
|
||||
op_write(struct file *f, off_t pos, off_t len)
|
||||
{
|
||||
off_t amount;
|
||||
void op_write(struct file *f, off_t pos, off_t len) {
|
||||
off_t amount;
|
||||
|
||||
while (len > 0) {
|
||||
amount = len;
|
||||
if (amount > DATA_MAXSIZE) {
|
||||
amount = DATA_MAXSIZE;
|
||||
}
|
||||
while (len > 0) {
|
||||
amount = len;
|
||||
if (amount > DATA_MAXSIZE) {
|
||||
amount = DATA_MAXSIZE;
|
||||
}
|
||||
|
||||
if (checkmode) {
|
||||
check_write(f->handle, f->name, f->testcode, f->seq,
|
||||
pos, amount);
|
||||
}
|
||||
else {
|
||||
do_write(f->handle, f->name, f->testcode, f->seq,
|
||||
pos, amount);
|
||||
}
|
||||
f->seq++;
|
||||
pos += amount;
|
||||
len -= amount;
|
||||
}
|
||||
if (checkmode) {
|
||||
check_write(f->handle, f->name, f->testcode, f->seq, pos, amount);
|
||||
} else {
|
||||
do_write(f->handle, f->name, f->testcode, f->seq, pos, amount);
|
||||
}
|
||||
f->seq++;
|
||||
pos += amount;
|
||||
len -= amount;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_truncate(struct file *f, off_t len)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_truncate(f->handle, f->name, len);
|
||||
}
|
||||
else {
|
||||
do_truncate(f->handle, f->name, len);
|
||||
}
|
||||
void op_truncate(struct file *f, off_t len) {
|
||||
if (checkmode) {
|
||||
check_truncate(f->handle, f->name, len);
|
||||
} else {
|
||||
do_truncate(f->handle, f->name, len);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// dirops
|
||||
|
||||
void
|
||||
op_mkdir(unsigned name)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_mkdir(name);
|
||||
}
|
||||
else {
|
||||
do_mkdir(name);
|
||||
}
|
||||
void op_mkdir(unsigned name) {
|
||||
if (checkmode) {
|
||||
check_mkdir(name);
|
||||
} else {
|
||||
do_mkdir(name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_rmdir(unsigned name)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_rmdir(name);
|
||||
}
|
||||
else {
|
||||
do_rmdir(name);
|
||||
}
|
||||
void op_rmdir(unsigned name) {
|
||||
if (checkmode) {
|
||||
check_rmdir(name);
|
||||
} else {
|
||||
do_rmdir(name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_unlink(unsigned name)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_unlink(name);
|
||||
}
|
||||
else {
|
||||
do_unlink(name);
|
||||
}
|
||||
void op_unlink(unsigned name) {
|
||||
if (checkmode) {
|
||||
check_unlink(name);
|
||||
} else {
|
||||
do_unlink(name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_link(unsigned from, unsigned to)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_link(from, to);
|
||||
}
|
||||
else {
|
||||
do_link(from, to);
|
||||
}
|
||||
void op_link(unsigned from, unsigned to) {
|
||||
if (checkmode) {
|
||||
check_link(from, to);
|
||||
} else {
|
||||
do_link(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_rename(unsigned from, unsigned to)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_rename(from, to);
|
||||
}
|
||||
else {
|
||||
do_rename(from, to);
|
||||
}
|
||||
void op_rename(unsigned from, unsigned to) {
|
||||
if (checkmode) {
|
||||
check_rename(from, to);
|
||||
} else {
|
||||
do_rename(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_renamexd(fromdir, from, todir, to);
|
||||
}
|
||||
else {
|
||||
do_renamexd(fromdir, from, todir, to);
|
||||
}
|
||||
void op_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to) {
|
||||
if (checkmode) {
|
||||
check_renamexd(fromdir, from, todir, to);
|
||||
} else {
|
||||
do_renamexd(fromdir, from, todir, to);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_chdir(unsigned name)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_chdir(name);
|
||||
}
|
||||
else {
|
||||
do_chdir(name);
|
||||
}
|
||||
void op_chdir(unsigned name) {
|
||||
if (checkmode) {
|
||||
check_chdir(name);
|
||||
} else {
|
||||
do_chdir(name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
op_chdirup(void)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_chdirup();
|
||||
}
|
||||
else {
|
||||
do_chdirup();
|
||||
}
|
||||
void op_chdirup(void) {
|
||||
if (checkmode) {
|
||||
check_chdirup();
|
||||
} else {
|
||||
do_chdirup();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// other
|
||||
|
||||
void
|
||||
op_sync(void)
|
||||
{
|
||||
if (checkmode) {
|
||||
check_sync();
|
||||
}
|
||||
else {
|
||||
do_sync();
|
||||
}
|
||||
void op_sync(void) {
|
||||
if (checkmode) {
|
||||
check_sync();
|
||||
} else {
|
||||
do_sync();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
complete(void)
|
||||
{
|
||||
if (checkmode) {
|
||||
checkfs();
|
||||
}
|
||||
void complete(void) {
|
||||
if (checkmode) {
|
||||
checkfs();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,37 +34,33 @@
|
||||
|
||||
#include "pool.h"
|
||||
|
||||
unsigned
|
||||
poolalloc(struct poolctl *pool)
|
||||
{
|
||||
uint32_t mask;
|
||||
unsigned j, i;
|
||||
unsigned poolalloc(struct poolctl *pool) {
|
||||
uint32_t mask;
|
||||
unsigned j, i;
|
||||
|
||||
assert(pool->max % 32 == 0);
|
||||
for (j=0; j<pool->max/32; j++) {
|
||||
for (mask=1, i=0; i<32; mask<<=1, i++) {
|
||||
if ((pool->inuse[j] & mask) == 0) {
|
||||
pool->inuse[j] |= mask;
|
||||
return j*32 + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
errx(1, "Too many %s -- increase %s in %s",
|
||||
pool->itemtype, pool->maxname, pool->file);
|
||||
return 0;
|
||||
assert(pool->max % 32 == 0);
|
||||
for (j = 0; j < pool->max / 32; j++) {
|
||||
for (mask = 1, i = 0; i < 32; mask <<= 1, i++) {
|
||||
if ((pool->inuse[j] & mask) == 0) {
|
||||
pool->inuse[j] |= mask;
|
||||
return j * 32 + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
errx(1, "Too many %s -- increase %s in %s", pool->itemtype, pool->maxname,
|
||||
pool->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
poolfree(struct poolctl *pool, unsigned num)
|
||||
{
|
||||
uint32_t mask;
|
||||
unsigned pos;
|
||||
void poolfree(struct poolctl *pool, unsigned num) {
|
||||
uint32_t mask;
|
||||
unsigned pos;
|
||||
|
||||
assert(num < pool->max);
|
||||
assert(num < pool->max);
|
||||
|
||||
pos = num / 32;
|
||||
mask = 1 << (num % 32);
|
||||
pos = num / 32;
|
||||
mask = 1 << (num % 32);
|
||||
|
||||
assert(pool->inuse[pos] & mask);
|
||||
pool->inuse[pos] &= ~(uint32_t)mask;
|
||||
assert(pool->inuse[pos] & mask);
|
||||
pool->inuse[pos] &= ~(uint32_t)mask;
|
||||
}
|
||||
|
||||
@@ -29,26 +29,24 @@
|
||||
*/
|
||||
|
||||
struct poolctl {
|
||||
uint32_t *inuse;
|
||||
unsigned max;
|
||||
const char *itemtype;
|
||||
const char *maxname;
|
||||
const char *file;
|
||||
uint32_t *inuse;
|
||||
unsigned max;
|
||||
const char *itemtype;
|
||||
const char *maxname;
|
||||
const char *file;
|
||||
};
|
||||
|
||||
#define DIVROUNDUP(a, b) (((a) + (b) - 1) / (b))
|
||||
#define ROUNDUP(a, b) (DIVROUNDUP(a, b) * (b))
|
||||
#define DIVROUNDUP(a, b) (((a) + (b) - 1) / (b))
|
||||
#define ROUNDUP(a, b) (DIVROUNDUP(a, b) * (b))
|
||||
|
||||
#define DECLPOOL(T, MAX) \
|
||||
static struct T pool_space_##T[ROUNDUP(MAX, 32)]; \
|
||||
static uint32_t pool_inuse_##T[DIVROUNDUP(MAX, 32)]; \
|
||||
static struct poolctl pool_##T = { \
|
||||
.inuse = pool_inuse_##T, \
|
||||
.max = ROUNDUP(MAX, 32), \
|
||||
.itemtype = "struct " #T, \
|
||||
.maxname = #MAX, \
|
||||
.file = __FILE__ \
|
||||
}
|
||||
#define DECLPOOL(T, MAX) \
|
||||
static struct T pool_space_##T[ROUNDUP(MAX, 32)]; \
|
||||
static uint32_t pool_inuse_##T[DIVROUNDUP(MAX, 32)]; \
|
||||
static struct poolctl pool_##T = {.inuse = pool_inuse_##T, \
|
||||
.max = ROUNDUP(MAX, 32), \
|
||||
.itemtype = "struct " #T, \
|
||||
.maxname = #MAX, \
|
||||
.file = __FILE__}
|
||||
|
||||
#define POOLALLOC(T) (&pool_space_##T[poolalloc(&pool_##T)])
|
||||
#define POOLFREE(T, x) (poolfree(&pool_##T, (x) - pool_space_##T))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The VFS-interface operations that can write to the fs are:
|
||||
*
|
||||
|
||||
@@ -49,35 +49,34 @@
|
||||
|
||||
#define HASHP 104729
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
char readbuf[1];
|
||||
int j = 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd;
|
||||
char readbuf[1];
|
||||
int j = 0;
|
||||
|
||||
#ifdef HOST
|
||||
hostcompat_init(argc, argv);
|
||||
hostcompat_init(argc, argv);
|
||||
#endif
|
||||
|
||||
if (argc != 2) {
|
||||
errx(1, "Usage: hash filename");
|
||||
}
|
||||
if (argc != 2) {
|
||||
errx(1, "Usage: hash filename");
|
||||
}
|
||||
|
||||
fd = open(argv[1], O_RDONLY, 0664);
|
||||
fd = open(argv[1], O_RDONLY, 0664);
|
||||
|
||||
if (fd<0) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
if (fd < 0) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (read(fd, readbuf, 1) <= 0) break;
|
||||
j = ((j*8) + (int) readbuf[0]) % HASHP;
|
||||
}
|
||||
for (;;) {
|
||||
if (read(fd, readbuf, 1) <= 0)
|
||||
break;
|
||||
j = ((j * 8) + (int)readbuf[0]) % HASHP;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
|
||||
printf("Hash : %d\n", j);
|
||||
printf("Hash : %d\n", j);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -34,20 +34,18 @@
|
||||
* Loops consuming CPU cycles.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
volatile int i;
|
||||
volatile int k, l, m;
|
||||
int main(void) {
|
||||
volatile int i;
|
||||
volatile int k, l, m;
|
||||
|
||||
k = 1283;
|
||||
l = 53;
|
||||
for (i=0; i<15000000; i++) {
|
||||
l = m + k;
|
||||
}
|
||||
k = 1283;
|
||||
l = 53;
|
||||
for (i = 0; i < 15000000; i++) {
|
||||
l = m + k;
|
||||
}
|
||||
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)l;
|
||||
// gcc 4.8 improperly demands this
|
||||
(void)l;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,45 +40,42 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PageSize 4096
|
||||
#define NumPages 512
|
||||
#define PageSize 4096
|
||||
#define NumPages 512
|
||||
|
||||
int sparse[NumPages][PageSize]; /* use only the first element in the row */
|
||||
int sparse[NumPages][PageSize]; /* use only the first element in the row */
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i,j;
|
||||
int main(void) {
|
||||
int i, j;
|
||||
|
||||
printf("Entering the huge program - I will stress test your VM\n");
|
||||
printf("Entering the huge program - I will stress test your VM\n");
|
||||
|
||||
/* move number in so that sparse[i][0]=i */
|
||||
for (i=0; i<NumPages; i++) {
|
||||
sparse[i][0]=i;
|
||||
}
|
||||
/* move number in so that sparse[i][0]=i */
|
||||
for (i = 0; i < NumPages; i++) {
|
||||
sparse[i][0] = i;
|
||||
}
|
||||
|
||||
printf("stage [1] done\n");
|
||||
printf("stage [1] done\n");
|
||||
|
||||
/* increment each location 5 times */
|
||||
for (j=0; j<5; j++) {
|
||||
for (i=0; i<NumPages; i++) {
|
||||
sparse[i][0]++;
|
||||
}
|
||||
printf("stage [2.%d] done\n", j);
|
||||
}
|
||||
/* increment each location 5 times */
|
||||
for (j = 0; j < 5; j++) {
|
||||
for (i = 0; i < NumPages; i++) {
|
||||
sparse[i][0]++;
|
||||
}
|
||||
printf("stage [2.%d] done\n", j);
|
||||
}
|
||||
|
||||
printf("stage [2] done\n");
|
||||
printf("stage [2] done\n");
|
||||
|
||||
/* check if the numbers are sane */
|
||||
for (i=NumPages-1; i>=0; i--) {
|
||||
if (sparse[i][0]!=i+5) {
|
||||
printf("BAD NEWS!!! - your VM mechanism has a bug!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
/* check if the numbers are sane */
|
||||
for (i = NumPages - 1; i >= 0; i--) {
|
||||
if (sparse[i][0] != i + 5) {
|
||||
printf("BAD NEWS!!! - your VM mechanism has a bug!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("You passed!\n");
|
||||
printf("You passed!\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,52 +49,45 @@
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#define _PATH_RANDOM "random:"
|
||||
|
||||
#define _PATH_RANDOM "random:"
|
||||
|
||||
#define SMALLSIZE 72
|
||||
#define MEDIUMSIZE 896
|
||||
#define BIGSIZE 16384
|
||||
#define HUGESIZE (1024 * 1024 * 1024)
|
||||
#define SMALLSIZE 72
|
||||
#define MEDIUMSIZE 896
|
||||
#define BIGSIZE 16384
|
||||
#define HUGESIZE (1024 * 1024 * 1024)
|
||||
|
||||
/* Maximum amount of space per block we allow for indexing structures */
|
||||
#define OVERHEAD 32
|
||||
#define OVERHEAD 32
|
||||
|
||||
/* Point past which we assume something else is going on */
|
||||
#define ABSURD_OVERHEAD 256
|
||||
#define ABSURD_OVERHEAD 256
|
||||
|
||||
static
|
||||
int
|
||||
geti(void)
|
||||
{
|
||||
int val=0;
|
||||
int ch, digits=0;
|
||||
static int geti(void) {
|
||||
int val = 0;
|
||||
int ch, digits = 0;
|
||||
|
||||
while (1) {
|
||||
ch = getchar();
|
||||
if (ch=='\n' || ch=='\r') {
|
||||
putchar('\n');
|
||||
break;
|
||||
}
|
||||
else if ((ch=='\b' || ch==127) && digits>0) {
|
||||
printf("\b \b");
|
||||
val = val/10;
|
||||
digits--;
|
||||
}
|
||||
else if (ch>='0' && ch<='9') {
|
||||
putchar(ch);
|
||||
val = val*10 + (ch-'0');
|
||||
digits++;
|
||||
}
|
||||
else {
|
||||
putchar('\a');
|
||||
}
|
||||
}
|
||||
while (1) {
|
||||
ch = getchar();
|
||||
if (ch == '\n' || ch == '\r') {
|
||||
putchar('\n');
|
||||
break;
|
||||
} else if ((ch == '\b' || ch == 127) && digits > 0) {
|
||||
printf("\b \b");
|
||||
val = val / 10;
|
||||
digits--;
|
||||
} else if (ch >= '0' && ch <= '9') {
|
||||
putchar(ch);
|
||||
val = val * 10 + (ch - '0');
|
||||
digits++;
|
||||
} else {
|
||||
putchar('\a');
|
||||
}
|
||||
}
|
||||
|
||||
if (digits==0) {
|
||||
return -1;
|
||||
}
|
||||
return val;
|
||||
if (digits == 0) {
|
||||
return -1;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -102,65 +95,60 @@ geti(void)
|
||||
/*
|
||||
* Fill a block of memory with a test pattern.
|
||||
*/
|
||||
static
|
||||
void
|
||||
markblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
|
||||
{
|
||||
size_t n, i;
|
||||
unsigned long *pl;
|
||||
unsigned long val;
|
||||
static void markblock(volatile void *ptr, size_t size, unsigned bias,
|
||||
int doprint) {
|
||||
size_t n, i;
|
||||
unsigned long *pl;
|
||||
unsigned long val;
|
||||
|
||||
pl = (unsigned long *)ptr;
|
||||
n = size / sizeof(unsigned long);
|
||||
pl = (unsigned long *)ptr;
|
||||
n = size / sizeof(unsigned long);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
val = ((unsigned long)i ^ (unsigned long)bias);
|
||||
pl[i] = val;
|
||||
if (doprint && (i%64==63)) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
if (doprint) {
|
||||
printf("\n");
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
val = ((unsigned long)i ^ (unsigned long)bias);
|
||||
pl[i] = val;
|
||||
if (doprint && (i % 64 == 63)) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
if (doprint) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check a block marked with markblock()
|
||||
*/
|
||||
static
|
||||
int
|
||||
checkblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
|
||||
{
|
||||
size_t n, i;
|
||||
unsigned long *pl;
|
||||
unsigned long val;
|
||||
static int checkblock(volatile void *ptr, size_t size, unsigned bias,
|
||||
int doprint) {
|
||||
size_t n, i;
|
||||
unsigned long *pl;
|
||||
unsigned long val;
|
||||
|
||||
pl = (unsigned long *)ptr;
|
||||
n = size / sizeof(unsigned long);
|
||||
pl = (unsigned long *)ptr;
|
||||
n = size / sizeof(unsigned long);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
val = ((unsigned long)i ^ (unsigned long)bias);
|
||||
if (pl[i] != val) {
|
||||
if (doprint) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("FAILED: data mismatch at offset %lu of block "
|
||||
"at 0x%lx: %lu vs. %lu\n",
|
||||
(unsigned long) (i*sizeof(unsigned long)),
|
||||
(unsigned long)(uintptr_t)pl,
|
||||
pl[i], val);
|
||||
return -1;
|
||||
}
|
||||
if (doprint && (i%64==63)) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
if (doprint) {
|
||||
printf("\n");
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
val = ((unsigned long)i ^ (unsigned long)bias);
|
||||
if (pl[i] != val) {
|
||||
if (doprint) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("FAILED: data mismatch at offset %lu of block "
|
||||
"at 0x%lx: %lu vs. %lu\n",
|
||||
(unsigned long)(i * sizeof(unsigned long)),
|
||||
(unsigned long)(uintptr_t)pl, pl[i], val);
|
||||
return -1;
|
||||
}
|
||||
if (doprint && (i % 64 == 63)) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
if (doprint) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -172,32 +160,28 @@ checkblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
|
||||
* allocated.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test1(void)
|
||||
{
|
||||
volatile unsigned *x;
|
||||
static void test1(void) {
|
||||
volatile unsigned *x;
|
||||
|
||||
printf("*** Malloc test 1 ***\n");
|
||||
printf("Allocating %u bytes\n", BIGSIZE);
|
||||
x = malloc(BIGSIZE);
|
||||
if (x==NULL) {
|
||||
printf("FAILED: malloc failed\n");
|
||||
return;
|
||||
}
|
||||
printf("*** Malloc test 1 ***\n");
|
||||
printf("Allocating %u bytes\n", BIGSIZE);
|
||||
x = malloc(BIGSIZE);
|
||||
if (x == NULL) {
|
||||
printf("FAILED: malloc failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
markblock(x, BIGSIZE, 0, 0);
|
||||
if (checkblock(x, BIGSIZE, 0, 0)) {
|
||||
printf("FAILED: data corrupt\n");
|
||||
return;
|
||||
}
|
||||
markblock(x, BIGSIZE, 0, 0);
|
||||
if (checkblock(x, BIGSIZE, 0, 0)) {
|
||||
printf("FAILED: data corrupt\n");
|
||||
return;
|
||||
}
|
||||
|
||||
free((void *)x);
|
||||
free((void *)x);
|
||||
|
||||
printf("Passed malloc test 1.\n");
|
||||
printf("Passed malloc test 1.\n");
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
@@ -230,53 +214,48 @@ test1(void)
|
||||
* available.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test2(void)
|
||||
{
|
||||
volatile unsigned *x;
|
||||
size_t size;
|
||||
static void test2(void) {
|
||||
volatile unsigned *x;
|
||||
size_t size;
|
||||
|
||||
printf("Entering malloc test 2.\n");
|
||||
printf("Make sure you read and understand the comment in malloctest.c "
|
||||
"that\nexplains the conditions this test assumes.\n\n");
|
||||
printf("Entering malloc test 2.\n");
|
||||
printf("Make sure you read and understand the comment in malloctest.c "
|
||||
"that\nexplains the conditions this test assumes.\n\n");
|
||||
|
||||
printf("Testing how much memory we can allocate:\n");
|
||||
printf("Testing how much memory we can allocate:\n");
|
||||
|
||||
for (size = HUGESIZE; (x = malloc(size))==NULL; size = size/2) {
|
||||
printf(" %9lu bytes: failed\n", (unsigned long) size);
|
||||
}
|
||||
printf(" %9lu bytes: succeeded\n", (unsigned long) size);
|
||||
for (size = HUGESIZE; (x = malloc(size)) == NULL; size = size / 2) {
|
||||
printf(" %9lu bytes: failed\n", (unsigned long)size);
|
||||
}
|
||||
printf(" %9lu bytes: succeeded\n", (unsigned long)size);
|
||||
|
||||
printf("Passed part 1\n");
|
||||
printf("Passed part 1\n");
|
||||
|
||||
printf("Touching all the words in the block.\n");
|
||||
markblock(x, size, 0, 1);
|
||||
printf("Touching all the words in the block.\n");
|
||||
markblock(x, size, 0, 1);
|
||||
|
||||
printf("Validating the words in the block.\n");
|
||||
if (checkblock(x, size, 0, 1)) {
|
||||
printf("FAILED: data corrupt\n");
|
||||
return;
|
||||
}
|
||||
printf("Passed part 2\n");
|
||||
printf("Validating the words in the block.\n");
|
||||
if (checkblock(x, size, 0, 1)) {
|
||||
printf("FAILED: data corrupt\n");
|
||||
return;
|
||||
}
|
||||
printf("Passed part 2\n");
|
||||
|
||||
printf("Freeing the block\n");
|
||||
free((void *)x);
|
||||
printf("Passed part 3\n");
|
||||
printf("Allocating another block\n");
|
||||
|
||||
printf("Freeing the block\n");
|
||||
free((void *)x);
|
||||
printf("Passed part 3\n");
|
||||
printf("Allocating another block\n");
|
||||
x = malloc(size);
|
||||
if (x == NULL) {
|
||||
printf("FAILED: free didn't return the memory?\n");
|
||||
return;
|
||||
}
|
||||
free((void *)x);
|
||||
|
||||
x = malloc(size);
|
||||
if (x==NULL) {
|
||||
printf("FAILED: free didn't return the memory?\n");
|
||||
return;
|
||||
}
|
||||
free((void *)x);
|
||||
|
||||
printf("Passed malloc test 2.\n");
|
||||
printf("Passed malloc test 2.\n");
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
@@ -291,92 +270,88 @@ test2(void)
|
||||
*/
|
||||
|
||||
struct test3 {
|
||||
struct test3 *next;
|
||||
char junk[(SMALLSIZE - sizeof(struct test3 *))];
|
||||
struct test3 *next;
|
||||
char junk[(SMALLSIZE - sizeof(struct test3 *))];
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
test3(void)
|
||||
{
|
||||
struct test3 *list = NULL, *tmp;
|
||||
size_t tot=0;
|
||||
int ct=0, failed=0;
|
||||
void *x;
|
||||
static void test3(void) {
|
||||
struct test3 *list = NULL, *tmp;
|
||||
size_t tot = 0;
|
||||
int ct = 0, failed = 0;
|
||||
void *x;
|
||||
|
||||
printf("Entering malloc test 3.\n");
|
||||
printf("Make sure you read and understand the comment in malloctest.c "
|
||||
"that\nexplains the conditions this test assumes.\n\n");
|
||||
printf("Entering malloc test 3.\n");
|
||||
printf("Make sure you read and understand the comment in malloctest.c "
|
||||
"that\nexplains the conditions this test assumes.\n\n");
|
||||
|
||||
printf("Testing how much memory we can allocate:\n");
|
||||
printf("Testing how much memory we can allocate:\n");
|
||||
|
||||
while ((tmp = malloc(sizeof(struct test3))) != NULL) {
|
||||
while ((tmp = malloc(sizeof(struct test3))) != NULL) {
|
||||
|
||||
assert(tmp != list);
|
||||
tmp->next = list;
|
||||
list = tmp;
|
||||
assert(tmp != list);
|
||||
tmp->next = list;
|
||||
list = tmp;
|
||||
|
||||
tot += sizeof(struct test3);
|
||||
tot += sizeof(struct test3);
|
||||
|
||||
markblock(list->junk, sizeof(list->junk), (uintptr_t)list, 0);
|
||||
markblock(list->junk, sizeof(list->junk), (uintptr_t)list, 0);
|
||||
|
||||
ct++;
|
||||
if (ct%128==0) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
ct++;
|
||||
if (ct % 128 == 0) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
|
||||
printf("Allocated %lu bytes\n", (unsigned long) tot);
|
||||
printf("Allocated %lu bytes\n", (unsigned long)tot);
|
||||
|
||||
printf("Trying some more allocations which I expect to fail...\n");
|
||||
printf("Trying some more allocations which I expect to fail...\n");
|
||||
|
||||
x = malloc(SMALLSIZE);
|
||||
if (x != NULL) {
|
||||
printf("FAILED: malloc(%u) succeeded\n", SMALLSIZE);
|
||||
return;
|
||||
}
|
||||
x = malloc(SMALLSIZE);
|
||||
if (x != NULL) {
|
||||
printf("FAILED: malloc(%u) succeeded\n", SMALLSIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
x = malloc(MEDIUMSIZE);
|
||||
if (x != NULL) {
|
||||
printf("FAILED: malloc(%u) succeeded\n", MEDIUMSIZE);
|
||||
return;
|
||||
}
|
||||
x = malloc(MEDIUMSIZE);
|
||||
if (x != NULL) {
|
||||
printf("FAILED: malloc(%u) succeeded\n", MEDIUMSIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
x = malloc(BIGSIZE);
|
||||
if (x != NULL) {
|
||||
printf("FAILED: malloc(%u) succeeded\n", BIGSIZE);
|
||||
return;
|
||||
}
|
||||
x = malloc(BIGSIZE);
|
||||
if (x != NULL) {
|
||||
printf("FAILED: malloc(%u) succeeded\n", BIGSIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Ok, now I'm going to free everything...\n");
|
||||
printf("Ok, now I'm going to free everything...\n");
|
||||
|
||||
while (list != NULL) {
|
||||
tmp = list->next;
|
||||
while (list != NULL) {
|
||||
tmp = list->next;
|
||||
|
||||
if (checkblock(list->junk, sizeof(list->junk),
|
||||
(uintptr_t)list, 0)) {
|
||||
failed = 1;
|
||||
}
|
||||
if (checkblock(list->junk, sizeof(list->junk), (uintptr_t)list, 0)) {
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
free(list);
|
||||
list = tmp;
|
||||
}
|
||||
free(list);
|
||||
list = tmp;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
printf("FAILED: data corruption\n");
|
||||
return;
|
||||
}
|
||||
if (failed) {
|
||||
printf("FAILED: data corruption\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Let me see if I can allocate some more now...\n");
|
||||
printf("Let me see if I can allocate some more now...\n");
|
||||
|
||||
x = malloc(MEDIUMSIZE);
|
||||
if (x == NULL) {
|
||||
printf("FAIL: Nope, I couldn't.\n");
|
||||
return;
|
||||
}
|
||||
free(x);
|
||||
x = malloc(MEDIUMSIZE);
|
||||
if (x == NULL) {
|
||||
printf("FAIL: Nope, I couldn't.\n");
|
||||
return;
|
||||
}
|
||||
free(x);
|
||||
|
||||
printf("Passed malloc test 3\n");
|
||||
printf("Passed malloc test 3\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -390,121 +365,117 @@ test3(void)
|
||||
* next-fit/best-fit algorithm is used.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test4(void)
|
||||
{
|
||||
void *x, *y, *z;
|
||||
unsigned long lx, ly, lz, overhead, zsize;
|
||||
static void test4(void) {
|
||||
void *x, *y, *z;
|
||||
unsigned long lx, ly, lz, overhead, zsize;
|
||||
|
||||
printf("Entering malloc test 4.\n");
|
||||
printf("This test is intended for first/best-fit based mallocs.\n");
|
||||
printf("This test may not work correctly if run after other tests.\n");
|
||||
printf("Entering malloc test 4.\n");
|
||||
printf("This test is intended for first/best-fit based mallocs.\n");
|
||||
printf("This test may not work correctly if run after other tests.\n");
|
||||
|
||||
printf("Testing free list coalescing:\n");
|
||||
printf("Testing free list coalescing:\n");
|
||||
|
||||
x = malloc(SMALLSIZE);
|
||||
if (x==NULL) {
|
||||
printf("FAILED: malloc(%u) failed\n", SMALLSIZE);
|
||||
return;
|
||||
}
|
||||
x = malloc(SMALLSIZE);
|
||||
if (x == NULL) {
|
||||
printf("FAILED: malloc(%u) failed\n", SMALLSIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
y = malloc(MEDIUMSIZE);
|
||||
if (y==NULL) {
|
||||
printf("FAILED: malloc(%u) failed\n", MEDIUMSIZE);
|
||||
return;
|
||||
}
|
||||
y = malloc(MEDIUMSIZE);
|
||||
if (y == NULL) {
|
||||
printf("FAILED: malloc(%u) failed\n", MEDIUMSIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sizeof(unsigned long) < sizeof(void *)) {
|
||||
printf("Buh? I can't fit a void * in an unsigned long\n");
|
||||
printf("ENVIRONMENT FAILED...\n");
|
||||
return;
|
||||
}
|
||||
if (sizeof(unsigned long) < sizeof(void *)) {
|
||||
printf("Buh? I can't fit a void * in an unsigned long\n");
|
||||
printf("ENVIRONMENT FAILED...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lx = (unsigned long)x;
|
||||
ly = (unsigned long)y;
|
||||
lx = (unsigned long)x;
|
||||
ly = (unsigned long)y;
|
||||
|
||||
printf("x is 0x%lx; y is 0x%lx\n", lx, ly);
|
||||
printf("x is 0x%lx; y is 0x%lx\n", lx, ly);
|
||||
|
||||
/*
|
||||
* The memory should look something like this:
|
||||
*
|
||||
* OXXXOYYYYYYYYYYY
|
||||
*
|
||||
* where O are optional overhead (indexing) blocks.
|
||||
*/
|
||||
/*
|
||||
* The memory should look something like this:
|
||||
*
|
||||
* OXXXOYYYYYYYYYYY
|
||||
*
|
||||
* where O are optional overhead (indexing) blocks.
|
||||
*/
|
||||
|
||||
/* This is obviously wrong. */
|
||||
if (lx == ly) {
|
||||
printf("FAIL: x == y\n");
|
||||
return;
|
||||
}
|
||||
/* This is obviously wrong. */
|
||||
if (lx == ly) {
|
||||
printf("FAIL: x == y\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for overlap. It is sufficient to check if the start
|
||||
* of each block is within the other block. (If the end of a
|
||||
* block is within the other block, either the start is too,
|
||||
* or the other block's start is within the first block.)
|
||||
*/
|
||||
if (lx < ly && lx + SMALLSIZE > ly) {
|
||||
printf("FAIL: y starts within x\n");
|
||||
return;
|
||||
}
|
||||
if (ly < lx && ly + MEDIUMSIZE > lx) {
|
||||
printf("FAIL: x starts within y\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Check for overlap. It is sufficient to check if the start
|
||||
* of each block is within the other block. (If the end of a
|
||||
* block is within the other block, either the start is too,
|
||||
* or the other block's start is within the first block.)
|
||||
*/
|
||||
if (lx < ly && lx + SMALLSIZE > ly) {
|
||||
printf("FAIL: y starts within x\n");
|
||||
return;
|
||||
}
|
||||
if (ly < lx && ly + MEDIUMSIZE > lx) {
|
||||
printf("FAIL: x starts within y\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If y is lower than x, some memory scheme we don't
|
||||
* understand is in use, or else there's already stuff on the
|
||||
* free list.
|
||||
*/
|
||||
if (ly < lx) {
|
||||
printf("TEST UNSUITABLE: y is below x\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If y is lower than x, some memory scheme we don't
|
||||
* understand is in use, or else there's already stuff on the
|
||||
* free list.
|
||||
*/
|
||||
if (ly < lx) {
|
||||
printf("TEST UNSUITABLE: y is below x\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the space used by index structures.
|
||||
*/
|
||||
overhead = ly - (lx + SMALLSIZE);
|
||||
printf("Apparent block overhead: %lu\n", overhead);
|
||||
/*
|
||||
* Compute the space used by index structures.
|
||||
*/
|
||||
overhead = ly - (lx + SMALLSIZE);
|
||||
printf("Apparent block overhead: %lu\n", overhead);
|
||||
|
||||
if (overhead > ABSURD_OVERHEAD) {
|
||||
printf("TEST UNSUITABLE: block overhead absurdly large.\n");
|
||||
return;
|
||||
}
|
||||
if (overhead > OVERHEAD) {
|
||||
printf("FAIL: block overhead is too large.\n");
|
||||
return;
|
||||
}
|
||||
if (overhead > ABSURD_OVERHEAD) {
|
||||
printf("TEST UNSUITABLE: block overhead absurdly large.\n");
|
||||
return;
|
||||
}
|
||||
if (overhead > OVERHEAD) {
|
||||
printf("FAIL: block overhead is too large.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Freeing blocks...\n");
|
||||
free(x);
|
||||
free(y);
|
||||
printf("Freeing blocks...\n");
|
||||
free(x);
|
||||
free(y);
|
||||
|
||||
zsize = SMALLSIZE + MEDIUMSIZE + overhead;
|
||||
zsize = SMALLSIZE + MEDIUMSIZE + overhead;
|
||||
|
||||
printf("Now allocating %lu bytes... should reuse the space.\n", zsize);
|
||||
z = malloc(zsize);
|
||||
if (z == NULL) {
|
||||
printf("FAIL: Allocation failed...\n");
|
||||
return;
|
||||
}
|
||||
printf("Now allocating %lu bytes... should reuse the space.\n", zsize);
|
||||
z = malloc(zsize);
|
||||
if (z == NULL) {
|
||||
printf("FAIL: Allocation failed...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lz = (unsigned long) z;
|
||||
lz = (unsigned long)z;
|
||||
|
||||
printf("z is 0x%lx (x was 0x%lx, y 0x%lx)\n", lz, lx, ly);
|
||||
printf("z is 0x%lx (x was 0x%lx, y 0x%lx)\n", lz, lx, ly);
|
||||
|
||||
if (lz==lx) {
|
||||
printf("Passed.\n");
|
||||
}
|
||||
else {
|
||||
printf("Failed.\n");
|
||||
}
|
||||
if (lz == lx) {
|
||||
printf("Passed.\n");
|
||||
} else {
|
||||
printf("Failed.\n");
|
||||
}
|
||||
|
||||
free(z);
|
||||
free(z);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -519,176 +490,152 @@ test4(void)
|
||||
* Test 7 asks for a seed.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test567(int testno, unsigned long seed)
|
||||
{
|
||||
static const int sizes[8] = { 13, 17, 69, 176, 433, 871, 1150, 6060 };
|
||||
static void test567(int testno, unsigned long seed) {
|
||||
static const int sizes[8] = {13, 17, 69, 176, 433, 871, 1150, 6060};
|
||||
|
||||
void *ptrs[32];
|
||||
int psizes[32];
|
||||
int i, n, size, failed=0;
|
||||
void *ptrs[32];
|
||||
int psizes[32];
|
||||
int i, n, size, failed = 0;
|
||||
|
||||
srandom(seed);
|
||||
printf("Seeded random number generator with %lu.\n", seed);
|
||||
srandom(seed);
|
||||
printf("Seeded random number generator with %lu.\n", seed);
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
ptrs[i] = NULL;
|
||||
psizes[i] = 0;
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
ptrs[i] = NULL;
|
||||
psizes[i] = 0;
|
||||
}
|
||||
|
||||
for (i=0; i<100000; i++) {
|
||||
n = random()%32;
|
||||
if (ptrs[n] == NULL) {
|
||||
size = sizes[random()%8];
|
||||
ptrs[n] = malloc(size);
|
||||
psizes[n] = size;
|
||||
if (ptrs[n] == NULL) {
|
||||
printf("\nmalloc %u failed\n", size);
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
markblock(ptrs[n], size, n, 0);
|
||||
}
|
||||
else {
|
||||
size = psizes[n];
|
||||
if (checkblock(ptrs[n], size, n, 0)) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
free(ptrs[n]);
|
||||
ptrs[n] = NULL;
|
||||
psizes[n] = 0;
|
||||
}
|
||||
if (i%256==0) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < 100000; i++) {
|
||||
n = random() % 32;
|
||||
if (ptrs[n] == NULL) {
|
||||
size = sizes[random() % 8];
|
||||
ptrs[n] = malloc(size);
|
||||
psizes[n] = size;
|
||||
if (ptrs[n] == NULL) {
|
||||
printf("\nmalloc %u failed\n", size);
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
markblock(ptrs[n], size, n, 0);
|
||||
} else {
|
||||
size = psizes[n];
|
||||
if (checkblock(ptrs[n], size, n, 0)) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
free(ptrs[n]);
|
||||
ptrs[n] = NULL;
|
||||
psizes[n] = 0;
|
||||
}
|
||||
if (i % 256 == 0) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (ptrs[i] != NULL) {
|
||||
free(ptrs[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (ptrs[i] != NULL) {
|
||||
free(ptrs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
printf("FAILED malloc test %d\n", testno);
|
||||
}
|
||||
else {
|
||||
printf("Passed malloc test %d\n", testno);
|
||||
}
|
||||
if (failed) {
|
||||
printf("FAILED malloc test %d\n", testno);
|
||||
} else {
|
||||
printf("Passed malloc test %d\n", testno);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test5(void)
|
||||
{
|
||||
printf("Beginning malloc test 5\n");
|
||||
test567(5, 0);
|
||||
static void test5(void) {
|
||||
printf("Beginning malloc test 5\n");
|
||||
test567(5, 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test6(void)
|
||||
{
|
||||
int fd, len;
|
||||
unsigned long seed;
|
||||
static void test6(void) {
|
||||
int fd, len;
|
||||
unsigned long seed;
|
||||
|
||||
printf("Beginning malloc test 6\n");
|
||||
printf("Beginning malloc test 6\n");
|
||||
|
||||
fd = open(_PATH_RANDOM, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", _PATH_RANDOM);
|
||||
}
|
||||
len = read(fd, &seed, sizeof(seed));
|
||||
if (len < 0) {
|
||||
err(1, "%s", _PATH_RANDOM);
|
||||
}
|
||||
else if (len < (int)sizeof(seed)) {
|
||||
errx(1, "%s: Short read", _PATH_RANDOM);
|
||||
}
|
||||
close(fd);
|
||||
fd = open(_PATH_RANDOM, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", _PATH_RANDOM);
|
||||
}
|
||||
len = read(fd, &seed, sizeof(seed));
|
||||
if (len < 0) {
|
||||
err(1, "%s", _PATH_RANDOM);
|
||||
} else if (len < (int)sizeof(seed)) {
|
||||
errx(1, "%s: Short read", _PATH_RANDOM);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
test567(6, seed);
|
||||
test567(6, seed);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test7(void)
|
||||
{
|
||||
unsigned long seed;
|
||||
static void test7(void) {
|
||||
unsigned long seed;
|
||||
|
||||
printf("Beginning malloc test 7\n");
|
||||
printf("Beginning malloc test 7\n");
|
||||
|
||||
printf("Enter random seed: ");
|
||||
seed = geti();
|
||||
printf("Enter random seed: ");
|
||||
seed = geti();
|
||||
|
||||
test567(7, seed);
|
||||
test567(7, seed);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static struct {
|
||||
int num;
|
||||
const char *desc;
|
||||
void (*func)(void);
|
||||
} tests[] = {
|
||||
{ 1, "Simple allocation test", test1 },
|
||||
{ 2, "Allocate all memory in a big chunk", test2 },
|
||||
{ 3, "Allocate all memory in small chunks", test3 },
|
||||
{ 4, "Free list coalescing test (first/next/best-fit only)", test4 },
|
||||
{ 5, "Stress test", test5 },
|
||||
{ 6, "Randomized stress test", test6 },
|
||||
{ 7, "Stress test with particular seed", test7 },
|
||||
{ -1, NULL, NULL }
|
||||
};
|
||||
int num;
|
||||
const char *desc;
|
||||
void (*func)(void);
|
||||
} tests[] = {{1, "Simple allocation test", test1},
|
||||
{2, "Allocate all memory in a big chunk", test2},
|
||||
{3, "Allocate all memory in small chunks", test3},
|
||||
{4, "Free list coalescing test (first/next/best-fit only)", test4},
|
||||
{5, "Stress test", test5},
|
||||
{6, "Randomized stress test", test6},
|
||||
{7, "Stress test with particular seed", test7},
|
||||
{-1, NULL, NULL}};
|
||||
|
||||
static
|
||||
int
|
||||
dotest(int tn)
|
||||
{
|
||||
int i;
|
||||
for (i=0; tests[i].num>=0; i++) {
|
||||
if (tests[i].num == tn) {
|
||||
tests[i].func();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
static int dotest(int tn) {
|
||||
int i;
|
||||
for (i = 0; tests[i].num >= 0; i++) {
|
||||
if (tests[i].num == tn) {
|
||||
tests[i].func();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, tn, menu=1;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, tn, menu = 1;
|
||||
|
||||
if (argc > 1) {
|
||||
for (i=1; i<argc; i++) {
|
||||
dotest(atoi(argv[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (argc > 1) {
|
||||
for (i = 1; i < argc; i++) {
|
||||
dotest(atoi(argv[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (menu) {
|
||||
for (i=0; tests[i].num>=0; i++) {
|
||||
printf(" %2d %s\n", tests[i].num,
|
||||
tests[i].desc);
|
||||
}
|
||||
menu = 0;
|
||||
}
|
||||
printf("malloctest: ");
|
||||
tn = geti();
|
||||
if (tn < 0) {
|
||||
break;
|
||||
}
|
||||
while (1) {
|
||||
if (menu) {
|
||||
for (i = 0; tests[i].num >= 0; i++) {
|
||||
printf(" %2d %s\n", tests[i].num, tests[i].desc);
|
||||
}
|
||||
menu = 0;
|
||||
}
|
||||
printf("malloctest: ");
|
||||
tn = geti();
|
||||
if (tn < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (dotest(tn)) {
|
||||
menu = 1;
|
||||
}
|
||||
}
|
||||
if (dotest(tn)) {
|
||||
menu = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,41 +48,39 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define Dim 360 /* sum total of the arrays doesn't fit in
|
||||
* physical memory
|
||||
*/
|
||||
#define Dim \
|
||||
360 /* sum total of the arrays doesn't fit in \
|
||||
* physical memory \
|
||||
*/
|
||||
|
||||
#define RIGHT 46397160 /* correct answer */
|
||||
#define RIGHT 46397160 /* correct answer */
|
||||
|
||||
int A[Dim][Dim];
|
||||
int B[Dim][Dim];
|
||||
int C[Dim][Dim];
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i, j, k, r;
|
||||
int main(void) {
|
||||
int i, j, k, r;
|
||||
|
||||
for (i = 0; i < Dim; i++) /* first initialize the matrices */
|
||||
for (j = 0; j < Dim; j++) {
|
||||
A[i][j] = i;
|
||||
B[i][j] = j;
|
||||
C[i][j] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < Dim; i++) /* then multiply them together */
|
||||
for (j = 0; j < Dim; j++)
|
||||
for (k = 0; k < Dim; k++)
|
||||
C[i][j] += A[i][k] * B[k][j];
|
||||
|
||||
printf("matmult-orig finished.\n");
|
||||
r = C[Dim-1][Dim-1];
|
||||
printf("answer is: %d (should be %d)\n", r, RIGHT);
|
||||
if (r != RIGHT) {
|
||||
printf("FAILED\n");
|
||||
for (i = 0; i < Dim; i++) /* first initialize the matrices */
|
||||
for (j = 0; j < Dim; j++) {
|
||||
A[i][j] = i;
|
||||
B[i][j] = j;
|
||||
C[i][j] = 0;
|
||||
}
|
||||
else {
|
||||
printf("Passed.\n");
|
||||
}
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < Dim; i++) /* then multiply them together */
|
||||
for (j = 0; j < Dim; j++)
|
||||
for (k = 0; k < Dim; k++)
|
||||
C[i][j] += A[i][k] * B[k][j];
|
||||
|
||||
printf("matmult-orig finished.\n");
|
||||
r = C[Dim - 1][Dim - 1];
|
||||
printf("answer is: %d (should be %d)\n", r, RIGHT);
|
||||
if (r != RIGHT) {
|
||||
printf("FAILED\n");
|
||||
} else {
|
||||
printf("Passed.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -42,49 +42,48 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define Dim 72 /* sum total of the arrays doesn't fit in
|
||||
* physical memory
|
||||
*/
|
||||
#define Dim \
|
||||
72 /* sum total of the arrays doesn't fit in \
|
||||
* physical memory \
|
||||
*/
|
||||
|
||||
#define RIGHT 8772192 /* correct answer */
|
||||
#define RIGHT 8772192 /* correct answer */
|
||||
|
||||
int A[Dim][Dim];
|
||||
int B[Dim][Dim];
|
||||
int C[Dim][Dim];
|
||||
int T[Dim][Dim][Dim];
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i, j, k, r;
|
||||
int main(void) {
|
||||
int i, j, k, r;
|
||||
|
||||
for (i = 0; i < Dim; i++) /* first initialize the matrices */
|
||||
for (j = 0; j < Dim; j++) {
|
||||
A[i][j] = i;
|
||||
B[i][j] = j;
|
||||
C[i][j] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < Dim; i++) /* then multiply them together */
|
||||
for (j = 0; j < Dim; j++)
|
||||
for (k = 0; k < Dim; k++)
|
||||
T[i][j][k] = A[i][k] * B[k][j];
|
||||
|
||||
for (i = 0; i < Dim; i++)
|
||||
for (j = 0; j < Dim; j++)
|
||||
for (k = 0; k < Dim; k++)
|
||||
C[i][j] += T[i][j][k];
|
||||
|
||||
r = 0;
|
||||
for (i = 0; i < Dim; i++)
|
||||
r += C[i][i];
|
||||
|
||||
printf("matmult finished.\n");
|
||||
printf("answer is: %d (should be %d)\n", r, RIGHT);
|
||||
if (r != RIGHT) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
for (i = 0; i < Dim; i++) /* first initialize the matrices */
|
||||
for (j = 0; j < Dim; j++) {
|
||||
A[i][j] = i;
|
||||
B[i][j] = j;
|
||||
C[i][j] = 0;
|
||||
}
|
||||
printf("Passed.\n");
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < Dim; i++) /* then multiply them together */
|
||||
for (j = 0; j < Dim; j++)
|
||||
for (k = 0; k < Dim; k++)
|
||||
T[i][j][k] = A[i][k] * B[k][j];
|
||||
|
||||
for (i = 0; i < Dim; i++)
|
||||
for (j = 0; j < Dim; j++)
|
||||
for (k = 0; k < Dim; k++)
|
||||
C[i][j] += T[i][j][k];
|
||||
|
||||
r = 0;
|
||||
for (i = 0; i < Dim; i++)
|
||||
r += C[i][i];
|
||||
|
||||
printf("matmult finished.\n");
|
||||
printf("answer is: %d (should be %d)\n", r, RIGHT);
|
||||
if (r != RIGHT) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Passed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -81,74 +81,52 @@
|
||||
*/
|
||||
|
||||
struct usem {
|
||||
char name[32];
|
||||
int fd;
|
||||
char name[32];
|
||||
int fd;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
semcreate(const char *tag, struct usem *sem)
|
||||
{
|
||||
int fd;
|
||||
static void semcreate(const char *tag, struct usem *sem) {
|
||||
int fd;
|
||||
|
||||
snprintf(sem->name, sizeof(sem->name), "sem:multiexec.%s.%d",
|
||||
tag, (int)getpid());
|
||||
snprintf(sem->name, sizeof(sem->name), "sem:multiexec.%s.%d", tag,
|
||||
(int)getpid());
|
||||
|
||||
fd = open(sem->name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(fd);
|
||||
fd = open(sem->name, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semopen(struct usem *sem)
|
||||
{
|
||||
sem->fd = open(sem->name, O_RDWR, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
static void semopen(struct usem *sem) {
|
||||
sem->fd = open(sem->name, O_RDWR, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semclose(struct usem *sem)
|
||||
{
|
||||
close(sem->fd);
|
||||
static void semclose(struct usem *sem) { close(sem->fd); }
|
||||
|
||||
static void semdestroy(struct usem *sem) { remove(sem->name); }
|
||||
|
||||
static void semP(struct usem *sem, size_t num) {
|
||||
char c[num];
|
||||
|
||||
if (read(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semdestroy(struct usem *sem)
|
||||
{
|
||||
remove(sem->name);
|
||||
}
|
||||
static void semV(struct usem *sem, size_t num) {
|
||||
char c[num];
|
||||
|
||||
static
|
||||
void
|
||||
semP(struct usem *sem, size_t num)
|
||||
{
|
||||
char c[num];
|
||||
/* semfs does not use these values, but be conservative */
|
||||
memset(c, 0, num);
|
||||
|
||||
if (read(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semV(struct usem *sem, size_t num)
|
||||
{
|
||||
char c[num];
|
||||
|
||||
/* semfs does not use these values, but be conservative */
|
||||
memset(c, 0, num);
|
||||
|
||||
if (write(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
if (write(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -158,115 +136,105 @@ semV(struct usem *sem, size_t num)
|
||||
static char *subargv[SUBARGC_MAX];
|
||||
static int subargc = 0;
|
||||
|
||||
static
|
||||
void
|
||||
spawn(int njobs)
|
||||
{
|
||||
struct usem s1, s2;
|
||||
pid_t pids[njobs];
|
||||
int failed, status;
|
||||
int i;
|
||||
static void spawn(int njobs) {
|
||||
struct usem s1, s2;
|
||||
pid_t pids[njobs];
|
||||
int failed, status;
|
||||
int i;
|
||||
|
||||
semcreate("1", &s1);
|
||||
semcreate("2", &s2);
|
||||
semcreate("1", &s1);
|
||||
semcreate("2", &s2);
|
||||
|
||||
printf("Forking %d child processes...\n", njobs);
|
||||
printf("Forking %d child processes...\n", njobs);
|
||||
|
||||
for (i=0; i<njobs; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i] == -1) {
|
||||
/* continue with the procs we have; cannot kill them */
|
||||
warn("fork");
|
||||
warnx("*** Only started %u processes ***", i);
|
||||
njobs = i;
|
||||
break;
|
||||
}
|
||||
if (pids[i] == 0) {
|
||||
/* child */
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
semV(&s1, 1);
|
||||
semP(&s2, 1);
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
execv(subargv[0], subargv);
|
||||
warn("execv: %s", subargv[0]);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < njobs; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i] == -1) {
|
||||
/* continue with the procs we have; cannot kill them */
|
||||
warn("fork");
|
||||
warnx("*** Only started %u processes ***", i);
|
||||
njobs = i;
|
||||
break;
|
||||
}
|
||||
if (pids[i] == 0) {
|
||||
/* child */
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
semV(&s1, 1);
|
||||
semP(&s2, 1);
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
execv(subargv[0], subargv);
|
||||
warn("execv: %s", subargv[0]);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
printf("Waiting for fork...\n");
|
||||
semP(&s1, njobs);
|
||||
printf("Starting the execs...\n");
|
||||
semV(&s2, njobs);
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
printf("Waiting for fork...\n");
|
||||
semP(&s1, njobs);
|
||||
printf("Starting the execs...\n");
|
||||
semV(&s2, njobs);
|
||||
|
||||
failed = 0;
|
||||
for (i=0; i<njobs; i++) {
|
||||
if (waitpid(pids[i], &status, 0) < 0) {
|
||||
warn("waitpid");
|
||||
failed++;
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d (child %d): Signal %d",
|
||||
(int)pids[i], i, WTERMSIG(status));
|
||||
failed++;
|
||||
}
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d (child %d): Exit %d",
|
||||
(int)pids[i], i, WEXITSTATUS(status));
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
if (failed > 0) {
|
||||
warnx("%d children failed", failed);
|
||||
}
|
||||
else {
|
||||
printf("Succeeded\n");
|
||||
}
|
||||
failed = 0;
|
||||
for (i = 0; i < njobs; i++) {
|
||||
if (waitpid(pids[i], &status, 0) < 0) {
|
||||
warn("waitpid");
|
||||
failed++;
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d (child %d): Signal %d", (int)pids[i], i, WTERMSIG(status));
|
||||
failed++;
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d (child %d): Exit %d", (int)pids[i], i, WEXITSTATUS(status));
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
if (failed > 0) {
|
||||
warnx("%d children failed", failed);
|
||||
} else {
|
||||
printf("Succeeded\n");
|
||||
}
|
||||
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
semdestroy(&s1);
|
||||
semdestroy(&s2);
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
semdestroy(&s1);
|
||||
semdestroy(&s2);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
static char default_prog[] = "/bin/pwd";
|
||||
int main(int argc, char *argv[]) {
|
||||
static char default_prog[] = "/bin/pwd";
|
||||
|
||||
int njobs = 12;
|
||||
int i;
|
||||
int njobs = 12;
|
||||
int i;
|
||||
|
||||
for (i=1; i<argc; i++) {
|
||||
if (!strcmp(argv[i], "-j")) {
|
||||
i++;
|
||||
if (argv[i] == NULL) {
|
||||
errx(1, "Option -j requires an argument");
|
||||
}
|
||||
njobs = atoi(argv[i]);
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-j")) {
|
||||
i++;
|
||||
if (argv[i] == NULL) {
|
||||
errx(1, "Option -j requires an argument");
|
||||
}
|
||||
njobs = atoi(argv[i]);
|
||||
}
|
||||
#if 0 /* XXX we apparently don't have strncmp? */
|
||||
else if (!strncmp(argv[i], "-j", 2)) {
|
||||
njobs = atoi(argv[i] + 2);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
subargv[subargc++] = argv[i];
|
||||
if (subargc >= SUBARGC_MAX) {
|
||||
errx(1, "Too many arguments");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
subargv[subargc++] = argv[i];
|
||||
if (subargc >= SUBARGC_MAX) {
|
||||
errx(1, "Too many arguments");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subargc == 0) {
|
||||
subargv[subargc++] = default_prog;
|
||||
}
|
||||
subargv[subargc] = NULL;
|
||||
if (subargc == 0) {
|
||||
subargv[subargc++] = default_prog;
|
||||
}
|
||||
subargv[subargc] = NULL;
|
||||
|
||||
spawn(njobs);
|
||||
spawn(njobs);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,19 +29,19 @@
|
||||
|
||||
/*
|
||||
|
||||
Test suite.
|
||||
Test suite.
|
||||
|
||||
This program takes the palindrome below and checks if it's
|
||||
a palindrome or not. It will hopefully exhibit an interesting
|
||||
page fault pattern.
|
||||
This program takes the palindrome below and checks if it's
|
||||
a palindrome or not. It will hopefully exhibit an interesting
|
||||
page fault pattern.
|
||||
|
||||
The palindrome was taken from
|
||||
The palindrome was taken from
|
||||
|
||||
http://www.cs.brown.edu/people/nfp/palindrome.html
|
||||
http://www.cs.brown.edu/people/nfp/palindrome.html
|
||||
|
||||
This is not large enough to really stress the VM system, but
|
||||
might be useful for testing in the early stages of the VM
|
||||
assignment.
|
||||
This is not large enough to really stress the VM system, but
|
||||
might be useful for testing in the early stages of the VM
|
||||
assignment.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -85,114 +85,112 @@ a canal - Panama!
|
||||
#include <string.h>
|
||||
|
||||
char palindrome[8000] =
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama"
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama"
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama"
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama";
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama"
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama"
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama"
|
||||
"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil"
|
||||
"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla"
|
||||
"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya"
|
||||
"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga"
|
||||
"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora"
|
||||
"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga"
|
||||
"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada"
|
||||
"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua"
|
||||
"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda"
|
||||
"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara"
|
||||
"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa"
|
||||
"localagarabaronamataragagapataradecalatotaledaticabardalegaboga"
|
||||
"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala"
|
||||
"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera"
|
||||
"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam"
|
||||
"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa"
|
||||
"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta"
|
||||
"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday"
|
||||
"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla"
|
||||
"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona"
|
||||
"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama";
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
char *start, *end;
|
||||
int main(void) {
|
||||
char *start, *end;
|
||||
|
||||
printf("Welcome to the palindrome tester!\n");
|
||||
printf("I will take a large palindrome and test it.\n");
|
||||
printf("Here it is:\n");
|
||||
printf("%s\n", palindrome);
|
||||
printf("Welcome to the palindrome tester!\n");
|
||||
printf("I will take a large palindrome and test it.\n");
|
||||
printf("Here it is:\n");
|
||||
printf("%s\n", palindrome);
|
||||
|
||||
printf("Testing...");
|
||||
/* skip to end */
|
||||
end = palindrome+strlen(palindrome);
|
||||
end--;
|
||||
printf("Testing...");
|
||||
/* skip to end */
|
||||
end = palindrome + strlen(palindrome);
|
||||
end--;
|
||||
|
||||
for (start = palindrome; start <= end; start++, end--) {
|
||||
putchar('.');
|
||||
if (*start != *end) {
|
||||
printf("NOT a palindrome\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (start = palindrome; start <= end; start++, end--) {
|
||||
putchar('.');
|
||||
if (*start != *end) {
|
||||
printf("NOT a palindrome\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("IS a palindrome\n");
|
||||
return 0;
|
||||
printf("IS a palindrome\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,43 +46,23 @@
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
|
||||
#define NJOBS 24
|
||||
#define NJOBS 24
|
||||
|
||||
#define DIM 35
|
||||
#define NMATS 11
|
||||
#define JOBSIZE ((NMATS+1)*DIM*DIM*sizeof(int))
|
||||
#define DIM 35
|
||||
#define NMATS 11
|
||||
#define JOBSIZE ((NMATS + 1) * DIM * DIM * sizeof(int))
|
||||
|
||||
static const int right_answers[NJOBS] = {
|
||||
-1337312809,
|
||||
356204544,
|
||||
-537881911,
|
||||
-65406976,
|
||||
1952063315,
|
||||
-843894784,
|
||||
1597000869,
|
||||
-993925120,
|
||||
838840559,
|
||||
-1616928768,
|
||||
-182386335,
|
||||
-364554240,
|
||||
251084843,
|
||||
-61403136,
|
||||
295326333,
|
||||
1488013312,
|
||||
1901440647,
|
||||
0,
|
||||
-1901440647,
|
||||
-1488013312,
|
||||
-295326333,
|
||||
61403136,
|
||||
-251084843,
|
||||
364554240,
|
||||
-1337312809, 356204544, -537881911, -65406976, 1952063315, -843894784,
|
||||
1597000869, -993925120, 838840559, -1616928768, -182386335, -364554240,
|
||||
251084843, -61403136, 295326333, 1488013312, 1901440647, 0,
|
||||
-1901440647, -1488013312, -295326333, 61403136, -251084843, 364554240,
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
struct matrix {
|
||||
int m_data[DIM][DIM];
|
||||
int m_data[DIM][DIM];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -91,129 +71,100 @@ struct matrix {
|
||||
* Use this instead of just calling printf so we know each printout
|
||||
* is atomic; this prevents the lines from getting intermingled.
|
||||
*/
|
||||
static
|
||||
void
|
||||
say(const char *fmt, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
write(STDOUT_FILENO, buf, strlen(buf));
|
||||
static void say(const char *fmt, ...) {
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
write(STDOUT_FILENO, buf, strlen(buf));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
multiply(struct matrix *res, const struct matrix *m1, const struct matrix *m2)
|
||||
{
|
||||
int i, j, k;
|
||||
static void multiply(struct matrix *res, const struct matrix *m1,
|
||||
const struct matrix *m2) {
|
||||
int i, j, k;
|
||||
|
||||
for (i=0; i<DIM; i++) {
|
||||
for (j=0; j<DIM; j++) {
|
||||
int val=0;
|
||||
for (k=0; k<DIM; k++) {
|
||||
val += m1->m_data[i][k]*m2->m_data[k][j];
|
||||
}
|
||||
res->m_data[i][j] = val;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < DIM; i++) {
|
||||
for (j = 0; j < DIM; j++) {
|
||||
int val = 0;
|
||||
for (k = 0; k < DIM; k++) {
|
||||
val += m1->m_data[i][k] * m2->m_data[k][j];
|
||||
}
|
||||
res->m_data[i][j] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
addeq(struct matrix *m1, const struct matrix *m2)
|
||||
{
|
||||
int i, j;
|
||||
for (i=0; i<DIM; i++) {
|
||||
for (j=0; j<DIM; j++) {
|
||||
m1->m_data[i][j] += m2->m_data[i][j];
|
||||
}
|
||||
}
|
||||
static void addeq(struct matrix *m1, const struct matrix *m2) {
|
||||
int i, j;
|
||||
for (i = 0; i < DIM; i++) {
|
||||
for (j = 0; j < DIM; j++) {
|
||||
m1->m_data[i][j] += m2->m_data[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
trace(const struct matrix *m1)
|
||||
{
|
||||
int i, t=0;
|
||||
for (i=0; i<DIM; i++) {
|
||||
t += m1->m_data[i][i];
|
||||
}
|
||||
return t;
|
||||
static int trace(const struct matrix *m1) {
|
||||
int i, t = 0;
|
||||
for (i = 0; i < DIM; i++) {
|
||||
t += m1->m_data[i][i];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static struct matrix mats[NMATS];
|
||||
|
||||
static
|
||||
void
|
||||
populate_initial_matrixes(int mynum)
|
||||
{
|
||||
int i,j;
|
||||
struct matrix *m = &mats[0];
|
||||
for (i=0; i<DIM; i++) {
|
||||
for (j=0; j<DIM; j++) {
|
||||
m->m_data[i][j] = mynum+i-2*j;
|
||||
}
|
||||
}
|
||||
static void populate_initial_matrixes(int mynum) {
|
||||
int i, j;
|
||||
struct matrix *m = &mats[0];
|
||||
for (i = 0; i < DIM; i++) {
|
||||
for (j = 0; j < DIM; j++) {
|
||||
m->m_data[i][j] = mynum + i - 2 * j;
|
||||
}
|
||||
}
|
||||
|
||||
multiply(&mats[1], &mats[0], &mats[0]);
|
||||
multiply(&mats[1], &mats[0], &mats[0]);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
compute(int n)
|
||||
{
|
||||
struct matrix tmp;
|
||||
int i, j;
|
||||
static void compute(int n) {
|
||||
struct matrix tmp;
|
||||
int i, j;
|
||||
|
||||
for (i=0,j=n-1; i<j; i++,j--) {
|
||||
multiply(&tmp, &mats[i], &mats[j]);
|
||||
addeq(&mats[n], &tmp);
|
||||
}
|
||||
for (i = 0, j = n - 1; i < j; i++, j--) {
|
||||
multiply(&tmp, &mats[i], &mats[j]);
|
||||
addeq(&mats[n], &tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
computeall(int mynum)
|
||||
{
|
||||
int i;
|
||||
populate_initial_matrixes(mynum);
|
||||
for (i=2; i<NMATS; i++) {
|
||||
compute(i);
|
||||
}
|
||||
static void computeall(int mynum) {
|
||||
int i;
|
||||
populate_initial_matrixes(mynum);
|
||||
for (i = 2; i < NMATS; i++) {
|
||||
compute(i);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
answer(void)
|
||||
{
|
||||
return trace(&mats[NMATS-1]);
|
||||
}
|
||||
static int answer(void) { return trace(&mats[NMATS - 1]); }
|
||||
|
||||
static
|
||||
void
|
||||
go(int mynum)
|
||||
{
|
||||
int r;
|
||||
static void go(int mynum) {
|
||||
int r;
|
||||
|
||||
say("Process %d (pid %d) starting computation...\n", mynum,
|
||||
(int) getpid());
|
||||
say("Process %d (pid %d) starting computation...\n", mynum, (int)getpid());
|
||||
|
||||
computeall(mynum);
|
||||
r = answer();
|
||||
computeall(mynum);
|
||||
r = answer();
|
||||
|
||||
if (r != right_answers[mynum]) {
|
||||
say("Process %d answer %d: FAILED, should be %d\n",
|
||||
mynum, r, right_answers[mynum]);
|
||||
exit(1);
|
||||
}
|
||||
say("Process %d answer %d: passed\n", mynum, r);
|
||||
exit(0);
|
||||
if (r != right_answers[mynum]) {
|
||||
say("Process %d answer %d: FAILED, should be %d\n", mynum, r,
|
||||
right_answers[mynum]);
|
||||
exit(1);
|
||||
}
|
||||
say("Process %d answer %d: passed\n", mynum, r);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -235,191 +186,157 @@ go(int mynum)
|
||||
*/
|
||||
|
||||
struct usem {
|
||||
char name[32];
|
||||
int fd;
|
||||
char name[32];
|
||||
int fd;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
semcreate(const char *tag, struct usem *sem)
|
||||
{
|
||||
int fd;
|
||||
static void semcreate(const char *tag, struct usem *sem) {
|
||||
int fd;
|
||||
|
||||
snprintf(sem->name, sizeof(sem->name), "sem:parallelvm.%s.%d",
|
||||
tag, (int)getpid());
|
||||
snprintf(sem->name, sizeof(sem->name), "sem:parallelvm.%s.%d", tag,
|
||||
(int)getpid());
|
||||
|
||||
fd = open(sem->name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(fd);
|
||||
fd = open(sem->name, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semopen(struct usem *sem)
|
||||
{
|
||||
sem->fd = open(sem->name, O_RDWR, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
static void semopen(struct usem *sem) {
|
||||
sem->fd = open(sem->name, O_RDWR, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semclose(struct usem *sem)
|
||||
{
|
||||
close(sem->fd);
|
||||
static void semclose(struct usem *sem) { close(sem->fd); }
|
||||
|
||||
static void semdestroy(struct usem *sem) { remove(sem->name); }
|
||||
|
||||
static void semP(struct usem *sem, size_t num) {
|
||||
char c[num];
|
||||
|
||||
if (read(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semdestroy(struct usem *sem)
|
||||
{
|
||||
remove(sem->name);
|
||||
}
|
||||
static void semV(struct usem *sem, size_t num) {
|
||||
char c[num];
|
||||
|
||||
static
|
||||
void
|
||||
semP(struct usem *sem, size_t num)
|
||||
{
|
||||
char c[num];
|
||||
/* semfs does not use these values, but be conservative */
|
||||
memset(c, 0, num);
|
||||
|
||||
if (read(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
semV(struct usem *sem, size_t num)
|
||||
{
|
||||
char c[num];
|
||||
|
||||
/* semfs does not use these values, but be conservative */
|
||||
memset(c, 0, num);
|
||||
|
||||
if (write(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
if (write(sem->fd, c, num) < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// driver
|
||||
|
||||
static
|
||||
int
|
||||
status_is_failure(int status)
|
||||
{
|
||||
/* Proper interpretation of Unix exit status */
|
||||
if (WIFSIGNALED(status)) {
|
||||
return 1;
|
||||
}
|
||||
if (!WIFEXITED(status)) {
|
||||
/* ? */
|
||||
return 1;
|
||||
}
|
||||
status = WEXITSTATUS(status);
|
||||
return status != 0;
|
||||
static int status_is_failure(int status) {
|
||||
/* Proper interpretation of Unix exit status */
|
||||
if (WIFSIGNALED(status)) {
|
||||
return 1;
|
||||
}
|
||||
if (!WIFEXITED(status)) {
|
||||
/* ? */
|
||||
return 1;
|
||||
}
|
||||
status = WEXITSTATUS(status);
|
||||
return status != 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
makeprocs(bool dowait)
|
||||
{
|
||||
int i, status, failcount;
|
||||
struct usem s1, s2;
|
||||
pid_t pids[NJOBS];
|
||||
static void makeprocs(bool dowait) {
|
||||
int i, status, failcount;
|
||||
struct usem s1, s2;
|
||||
pid_t pids[NJOBS];
|
||||
|
||||
if (dowait) {
|
||||
semcreate("1", &s1);
|
||||
semcreate("2", &s2);
|
||||
}
|
||||
if (dowait) {
|
||||
semcreate("1", &s1);
|
||||
semcreate("2", &s2);
|
||||
}
|
||||
|
||||
printf("Job size approximately %lu bytes\n", (unsigned long) JOBSIZE);
|
||||
printf("Forking %d jobs; total load %luk\n", NJOBS,
|
||||
(unsigned long) (NJOBS * JOBSIZE)/1024);
|
||||
printf("Job size approximately %lu bytes\n", (unsigned long)JOBSIZE);
|
||||
printf("Forking %d jobs; total load %luk\n", NJOBS,
|
||||
(unsigned long)(NJOBS * JOBSIZE) / 1024);
|
||||
|
||||
for (i=0; i<NJOBS; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i]<0) {
|
||||
warn("fork (process %d)", i);
|
||||
if (dowait) {
|
||||
semopen(&s1);
|
||||
semV(&s1, 1);
|
||||
semclose(&s1);
|
||||
}
|
||||
}
|
||||
if (pids[i]==0) {
|
||||
/* child */
|
||||
if (dowait) {
|
||||
say("Process %d forked\n", i);
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
semV(&s1, 1);
|
||||
semP(&s2, 1);
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
}
|
||||
go(i);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NJOBS; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i] < 0) {
|
||||
warn("fork (process %d)", i);
|
||||
if (dowait) {
|
||||
semopen(&s1);
|
||||
semV(&s1, 1);
|
||||
semclose(&s1);
|
||||
}
|
||||
}
|
||||
if (pids[i] == 0) {
|
||||
/* child */
|
||||
if (dowait) {
|
||||
say("Process %d forked\n", i);
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
semV(&s1, 1);
|
||||
semP(&s2, 1);
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
}
|
||||
go(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (dowait) {
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
say("Waiting for fork...\n");
|
||||
semP(&s1, NJOBS);
|
||||
say("Starting computation.\n");
|
||||
semV(&s2, NJOBS);
|
||||
}
|
||||
if (dowait) {
|
||||
semopen(&s1);
|
||||
semopen(&s2);
|
||||
say("Waiting for fork...\n");
|
||||
semP(&s1, NJOBS);
|
||||
say("Starting computation.\n");
|
||||
semV(&s2, NJOBS);
|
||||
}
|
||||
|
||||
failcount=0;
|
||||
for (i=0; i<NJOBS; i++) {
|
||||
if (pids[i]<0) {
|
||||
failcount++;
|
||||
}
|
||||
else {
|
||||
if (waitpid(pids[i], &status, 0)<0) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
if (status_is_failure(status)) {
|
||||
failcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
failcount = 0;
|
||||
for (i = 0; i < NJOBS; i++) {
|
||||
if (pids[i] < 0) {
|
||||
failcount++;
|
||||
} else {
|
||||
if (waitpid(pids[i], &status, 0) < 0) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
if (status_is_failure(status)) {
|
||||
failcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (failcount>0) {
|
||||
printf("%d subprocesses failed\n", failcount);
|
||||
exit(1);
|
||||
}
|
||||
printf("Test complete\n");
|
||||
if (failcount > 0) {
|
||||
printf("%d subprocesses failed\n", failcount);
|
||||
exit(1);
|
||||
}
|
||||
printf("Test complete\n");
|
||||
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
semdestroy(&s1);
|
||||
semdestroy(&s2);
|
||||
semclose(&s1);
|
||||
semclose(&s2);
|
||||
semdestroy(&s1);
|
||||
semdestroy(&s2);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bool dowait = false;
|
||||
int main(int argc, char *argv[]) {
|
||||
bool dowait = false;
|
||||
|
||||
if (argc == 0) {
|
||||
/* broken/unimplemented argv handling; do nothing */
|
||||
}
|
||||
else if (argc == 1) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (argc == 2 && !strcmp(argv[1], "-w")) {
|
||||
dowait = true;
|
||||
}
|
||||
else {
|
||||
printf("Usage: parallelvm [-w]\n");
|
||||
return 1;
|
||||
}
|
||||
makeprocs(dowait);
|
||||
return 0;
|
||||
if (argc == 0) {
|
||||
/* broken/unimplemented argv handling; do nothing */
|
||||
} else if (argc == 1) {
|
||||
/* nothing */
|
||||
} else if (argc == 2 && !strcmp(argv[1], "-w")) {
|
||||
dowait = true;
|
||||
} else {
|
||||
printf("Usage: parallelvm [-w]\n");
|
||||
return 1;
|
||||
}
|
||||
makeprocs(dowait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,29 +46,24 @@
|
||||
#define POISON_BYTE 0xa9
|
||||
#define BLOCKSIZE 512
|
||||
|
||||
static
|
||||
void
|
||||
poison(void)
|
||||
{
|
||||
char buf[BLOCKSIZE];
|
||||
off_t sectors, i;
|
||||
static void poison(void) {
|
||||
char buf[BLOCKSIZE];
|
||||
off_t sectors, i;
|
||||
|
||||
memset(buf, POISON_BYTE, sizeof(buf));
|
||||
memset(buf, POISON_BYTE, sizeof(buf));
|
||||
|
||||
sectors = diskblocks();
|
||||
for (i=0; i<sectors; i++) {
|
||||
diskwrite(buf, i);
|
||||
}
|
||||
sectors = diskblocks();
|
||||
for (i = 0; i < sectors; i++) {
|
||||
diskwrite(buf, i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
errx(1, "Usage: %s disk-image", argv[0]);
|
||||
}
|
||||
opendisk(argv[1]);
|
||||
poison();
|
||||
closedisk();
|
||||
return 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
errx(1, "Usage: %s disk-image", argv[0]);
|
||||
}
|
||||
opendisk(argv[1]);
|
||||
poison();
|
||||
closedisk();
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,134 +33,110 @@
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
static
|
||||
void
|
||||
randchar(char *c)
|
||||
{
|
||||
static void randchar(char *c) {
|
||||
#if RAND_MAX != 0x7fffffff
|
||||
#error "This code assumes RAND_MAX is 0x7fffffff"
|
||||
#endif
|
||||
|
||||
static long lbits = 0;
|
||||
static long lnum = 0;
|
||||
static long lbits = 0;
|
||||
static long lnum = 0;
|
||||
|
||||
long bit;
|
||||
int ct = 0;
|
||||
long bit;
|
||||
int ct = 0;
|
||||
|
||||
*c = 0;
|
||||
*c = 0;
|
||||
|
||||
while (ct < CHAR_BIT) {
|
||||
if (lnum==0) {
|
||||
lbits = random();
|
||||
lnum = 31;
|
||||
}
|
||||
while (ct < CHAR_BIT) {
|
||||
if (lnum == 0) {
|
||||
lbits = random();
|
||||
lnum = 31;
|
||||
}
|
||||
|
||||
bit = lbits & 1;
|
||||
if (bit) {
|
||||
(*c) |= 1;
|
||||
}
|
||||
(*c) <<= 1;
|
||||
ct++;
|
||||
lbits >>= 1;
|
||||
lnum--;
|
||||
}
|
||||
bit = lbits & 1;
|
||||
if (bit) {
|
||||
(*c) |= 1;
|
||||
}
|
||||
(*c) <<= 1;
|
||||
ct++;
|
||||
lbits >>= 1;
|
||||
lnum--;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
fillrand(void *p, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
char *cp = p;
|
||||
for (i=0; i<len; i++) {
|
||||
randchar(&cp[i]);
|
||||
}
|
||||
static void fillrand(void *p, size_t len) {
|
||||
size_t i;
|
||||
char *cp = p;
|
||||
for (i = 0; i < len; i++) {
|
||||
randchar(&cp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
randptr(void)
|
||||
{
|
||||
void *x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
void *randptr(void) {
|
||||
void *x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
int
|
||||
randint(void)
|
||||
{
|
||||
int x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
int randint(void) {
|
||||
int x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
off_t
|
||||
randoff(void)
|
||||
{
|
||||
off_t x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
off_t randoff(void) {
|
||||
off_t x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
size_t
|
||||
randsize(void)
|
||||
{
|
||||
size_t x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
size_t randsize(void) {
|
||||
size_t x;
|
||||
fillrand(&x, sizeof(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
printf("Usage: randcall [-f] [-c count] [-r seed] 2|3|4|all\n");
|
||||
printf(" -f suppress forking\n");
|
||||
printf(" -c set iteration count (default 100)\n");
|
||||
printf(" -r set pseudorandom seed (default 0)\n");
|
||||
exit(1);
|
||||
static void usage(void) {
|
||||
printf("Usage: randcall [-f] [-c count] [-r seed] 2|3|4|all\n");
|
||||
printf(" -f suppress forking\n");
|
||||
printf(" -c set iteration count (default 100)\n");
|
||||
printf(" -r set pseudorandom seed (default 0)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int count=100, seed = 0, dofork = 1;
|
||||
int an, i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int count = 100, seed = 0, dofork = 1;
|
||||
int an, i;
|
||||
|
||||
for (i=1; i<argc; i++) {
|
||||
if (!strcmp(argv[i], "-f")) {
|
||||
dofork = 0;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-c") && i<argc-1) {
|
||||
count = atoi(argv[++i]);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-r") && i<argc-1) {
|
||||
seed = atoi(argv[++i]);
|
||||
}
|
||||
else if (argv[i][0] == '-') {
|
||||
usage();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != argc-1) {
|
||||
usage();
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-f")) {
|
||||
dofork = 0;
|
||||
} else if (!strcmp(argv[i], "-c") && i < argc - 1) {
|
||||
count = atoi(argv[++i]);
|
||||
} else if (!strcmp(argv[i], "-r") && i < argc - 1) {
|
||||
seed = atoi(argv[++i]);
|
||||
} else if (argv[i][0] == '-') {
|
||||
usage();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != argc - 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "all")) {
|
||||
an = 5;
|
||||
}
|
||||
else {
|
||||
an = atoi(argv[i]);
|
||||
if (an <2 || an > 4) {
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if (!strcmp(argv[i], "all")) {
|
||||
an = 5;
|
||||
} else {
|
||||
an = atoi(argv[i]);
|
||||
if (an < 2 || an > 4) {
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
printf("Seed: %d Count: %d\n", seed, count);
|
||||
printf("Seed: %d Count: %d\n", seed, count);
|
||||
|
||||
srandom(seed);
|
||||
trycalls(an, dofork, count);
|
||||
srandom(seed);
|
||||
trycalls(an, dofork, count);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,148 +50,128 @@
|
||||
|
||||
static const char slogan[] = "CECIDI, ET NON SURGERE POSSUM!\n";
|
||||
|
||||
static
|
||||
int
|
||||
doopen(const char *path, int openflags)
|
||||
{
|
||||
int fd;
|
||||
static int doopen(const char *path, int openflags) {
|
||||
int fd;
|
||||
|
||||
fd = open(path, openflags, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
return fd;
|
||||
fd = open(path, openflags, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dodup2(int ofd, int nfd, const char *file)
|
||||
{
|
||||
int r;
|
||||
static void dodup2(int ofd, int nfd, const char *file) {
|
||||
int r;
|
||||
|
||||
r = dup2(ofd, nfd);
|
||||
if (r < 0) {
|
||||
err(1, "%s: dup2", file);
|
||||
}
|
||||
if (r != nfd) {
|
||||
errx(1, "%s: dup2: Expected %d, got %d", nfd, r);
|
||||
}
|
||||
r = dup2(ofd, nfd);
|
||||
if (r < 0) {
|
||||
err(1, "%s: dup2", file);
|
||||
}
|
||||
if (r != nfd) {
|
||||
errx(1, "%s: dup2: Expected %d, got %d", nfd, r);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
doclose(int fd, const char *file)
|
||||
{
|
||||
if (close(fd)) {
|
||||
warnx("%s: close", file);
|
||||
}
|
||||
static void doclose(int fd, const char *file) {
|
||||
if (close(fd)) {
|
||||
warnx("%s: close", file);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mkfile(void)
|
||||
{
|
||||
int fd;
|
||||
ssize_t r;
|
||||
static void mkfile(void) {
|
||||
int fd;
|
||||
ssize_t r;
|
||||
|
||||
fd = doopen(INFILE, O_WRONLY|O_CREAT|O_TRUNC);
|
||||
fd = doopen(INFILE, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
|
||||
r = write(fd, slogan, strlen(slogan));
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", INFILE);
|
||||
}
|
||||
if ((size_t)r != strlen(slogan)) {
|
||||
errx(1, "%s: write: Short count (got %zd, expected %zu)",
|
||||
INFILE, r, strlen(slogan));
|
||||
}
|
||||
r = write(fd, slogan, strlen(slogan));
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", INFILE);
|
||||
}
|
||||
if ((size_t)r != strlen(slogan)) {
|
||||
errx(1, "%s: write: Short count (got %zd, expected %zu)", INFILE, r,
|
||||
strlen(slogan));
|
||||
}
|
||||
|
||||
doclose(fd, INFILE);
|
||||
doclose(fd, INFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
chkfile(void)
|
||||
{
|
||||
char buf[256];
|
||||
ssize_t r;
|
||||
int fd;
|
||||
static void chkfile(void) {
|
||||
char buf[256];
|
||||
ssize_t r;
|
||||
int fd;
|
||||
|
||||
fd = doopen(OUTFILE, O_RDONLY);
|
||||
fd = doopen(OUTFILE, O_RDONLY);
|
||||
|
||||
r = read(fd, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
err(1, "%s: read", OUTFILE);
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "%s: read: Unexpected EOF", OUTFILE);
|
||||
}
|
||||
if ((size_t)r != strlen(slogan)) {
|
||||
errx(1, "%s: read: Short count (got %zd, expected %zu)",
|
||||
OUTFILE, r, strlen(slogan));
|
||||
}
|
||||
r = read(fd, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
err(1, "%s: read", OUTFILE);
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "%s: read: Unexpected EOF", OUTFILE);
|
||||
}
|
||||
if ((size_t)r != strlen(slogan)) {
|
||||
errx(1, "%s: read: Short count (got %zd, expected %zu)", OUTFILE, r,
|
||||
strlen(slogan));
|
||||
}
|
||||
|
||||
doclose(fd, OUTFILE);
|
||||
doclose(fd, OUTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
cat(void)
|
||||
{
|
||||
pid_t pid;
|
||||
int rfd, wfd, result, status;
|
||||
const char *args[2];
|
||||
static void cat(void) {
|
||||
pid_t pid;
|
||||
int rfd, wfd, result, status;
|
||||
const char *args[2];
|
||||
|
||||
rfd = doopen(INFILE, O_RDONLY);
|
||||
wfd = doopen(OUTFILE, O_WRONLY|O_CREAT|O_TRUNC);
|
||||
rfd = doopen(INFILE, O_RDONLY);
|
||||
wfd = doopen(OUTFILE, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
dodup2(rfd, STDIN_FILENO, INFILE);
|
||||
dodup2(wfd, STDOUT_FILENO, OUTFILE);
|
||||
doclose(rfd, INFILE);
|
||||
doclose(wfd, OUTFILE);
|
||||
args[0] = "cat";
|
||||
args[1] = NULL;
|
||||
execv(PATH_CAT, (char **)args);
|
||||
warn("%s: execv", PATH_CAT);
|
||||
_exit(1);
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
dodup2(rfd, STDIN_FILENO, INFILE);
|
||||
dodup2(wfd, STDOUT_FILENO, OUTFILE);
|
||||
doclose(rfd, INFILE);
|
||||
doclose(wfd, OUTFILE);
|
||||
args[0] = "cat";
|
||||
args[1] = NULL;
|
||||
execv(PATH_CAT, (char **)args);
|
||||
warn("%s: execv", PATH_CAT);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* parent */
|
||||
doclose(rfd, INFILE);
|
||||
doclose(wfd, OUTFILE);
|
||||
/* parent */
|
||||
doclose(rfd, INFILE);
|
||||
doclose(wfd, OUTFILE);
|
||||
|
||||
result = waitpid(pid, &status, 0);
|
||||
if (result == -1) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
errx(1, "pid %d: Signal %d", (int)pid, WTERMSIG(status));
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
errx(1, "pid %d: Exit %d", (int)pid, WEXITSTATUS(status));
|
||||
}
|
||||
result = waitpid(pid, &status, 0);
|
||||
if (result == -1) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
errx(1, "pid %d: Signal %d", (int)pid, WTERMSIG(status));
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
errx(1, "pid %d: Exit %d", (int)pid, WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
printf("Creating %s...\n", INFILE);
|
||||
mkfile();
|
||||
int main(void) {
|
||||
printf("Creating %s...\n", INFILE);
|
||||
mkfile();
|
||||
|
||||
printf("Running cat < %s > %s\n", INFILE, OUTFILE);
|
||||
cat();
|
||||
printf("Running cat < %s > %s\n", INFILE, OUTFILE);
|
||||
cat();
|
||||
|
||||
printf("Checking %s...\n", OUTFILE);
|
||||
chkfile();
|
||||
printf("Checking %s...\n", OUTFILE);
|
||||
chkfile();
|
||||
|
||||
printf("Passed.\n");
|
||||
(void)remove(INFILE);
|
||||
(void)remove(OUTFILE);
|
||||
return 0;
|
||||
printf("Passed.\n");
|
||||
(void)remove(INFILE);
|
||||
(void)remove(OUTFILE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
#include <limits.h>
|
||||
#include <err.h>
|
||||
|
||||
|
||||
static const char testdir[] = "testdir";
|
||||
static char startpoint[PATH_MAX - sizeof(testdir)];
|
||||
|
||||
@@ -55,21 +54,18 @@ static char startpoint[PATH_MAX - sizeof(testdir)];
|
||||
* where we came from.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
startup(void)
|
||||
{
|
||||
if (getcwd(startpoint, sizeof(startpoint))==NULL) {
|
||||
err(1, "getcwd (not in test dir)");
|
||||
}
|
||||
static void startup(void) {
|
||||
if (getcwd(startpoint, sizeof(startpoint)) == NULL) {
|
||||
err(1, "getcwd (not in test dir)");
|
||||
}
|
||||
|
||||
if (mkdir(testdir, 0775) < 0) {
|
||||
err(1, "%s: mkdir", testdir);
|
||||
}
|
||||
if (mkdir(testdir, 0775) < 0) {
|
||||
err(1, "%s: mkdir", testdir);
|
||||
}
|
||||
|
||||
if (chdir(testdir) < 0) {
|
||||
err(1, "%s: chdir", testdir);
|
||||
}
|
||||
if (chdir(testdir) < 0) {
|
||||
err(1, "%s: chdir", testdir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -80,16 +76,13 @@ startup(void)
|
||||
* from the current directory, which is justifiably prohibited.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
killdir(void)
|
||||
{
|
||||
char tmp[PATH_MAX];
|
||||
static void killdir(void) {
|
||||
char tmp[PATH_MAX];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", startpoint, testdir);
|
||||
if (rmdir(tmp)<0) {
|
||||
err(1, "%s: rmdir", tmp);
|
||||
}
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", startpoint, testdir);
|
||||
if (rmdir(tmp) < 0) {
|
||||
err(1, "%s: rmdir", tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -97,13 +90,10 @@ killdir(void)
|
||||
* can try again.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
finish(void)
|
||||
{
|
||||
if (chdir(startpoint)<0) {
|
||||
err(1, "%s: chdir", startpoint);
|
||||
}
|
||||
static void finish(void) {
|
||||
if (chdir(startpoint) < 0) {
|
||||
err(1, "%s: chdir", startpoint);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
@@ -112,293 +102,262 @@ finish(void)
|
||||
* Basic test - just try removing the directory without doing anything
|
||||
* evil.
|
||||
*/
|
||||
static
|
||||
void
|
||||
test1(void)
|
||||
{
|
||||
printf("Making %s\n", testdir);
|
||||
startup();
|
||||
static void test1(void) {
|
||||
printf("Making %s\n", testdir);
|
||||
startup();
|
||||
|
||||
printf("Removing %s while in it\n", testdir);
|
||||
killdir();
|
||||
printf("Removing %s while in it\n", testdir);
|
||||
killdir();
|
||||
|
||||
printf("Leaving the test directory\n");
|
||||
finish();
|
||||
printf("Leaving the test directory\n");
|
||||
finish();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now do it while we also have the directory open.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test2(void)
|
||||
{
|
||||
int fd;
|
||||
static void test2(void) {
|
||||
int fd;
|
||||
|
||||
printf("Now trying with the directory open...\n");
|
||||
startup();
|
||||
fd = open(".", O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, ".: open");
|
||||
}
|
||||
killdir();
|
||||
finish();
|
||||
printf("Now trying with the directory open...\n");
|
||||
startup();
|
||||
fd = open(".", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, ".: open");
|
||||
}
|
||||
killdir();
|
||||
finish();
|
||||
|
||||
/* close *after* leaving, just for excitement */
|
||||
if (close(fd)<0) {
|
||||
err(1, "removed %s: close", testdir);
|
||||
}
|
||||
/* close *after* leaving, just for excitement */
|
||||
if (close(fd) < 0) {
|
||||
err(1, "removed %s: close", testdir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now see if . and .. work after rmdir.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test3(void)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
int fd;
|
||||
static void test3(void) {
|
||||
char buf[PATH_MAX];
|
||||
int fd;
|
||||
|
||||
printf("Checking if . exists after rmdir\n");
|
||||
startup();
|
||||
killdir();
|
||||
printf("Checking if . exists after rmdir\n");
|
||||
startup();
|
||||
killdir();
|
||||
|
||||
fd = open(".", O_RDONLY);
|
||||
if (fd<0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, ".");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
close(fd);
|
||||
}
|
||||
fd = open(".", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, ".");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
fd = open("..", O_RDONLY);
|
||||
if (fd<0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "..");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnx("..: openable after rmdir - might be bad");
|
||||
close(fd);
|
||||
}
|
||||
fd = open("..", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "..");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
warnx("..: openable after rmdir - might be bad");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "../%s", testdir);
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd<0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "%s", buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
errx(1, "%s: works after rmdir", buf);
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "../%s", testdir);
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "%s", buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
errx(1, "%s: works after rmdir", buf);
|
||||
}
|
||||
|
||||
finish();
|
||||
finish();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now try to create files.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test4(void)
|
||||
{
|
||||
char buf[4096];
|
||||
int fd;
|
||||
static void test4(void) {
|
||||
char buf[4096];
|
||||
int fd;
|
||||
|
||||
printf("Checking if creating files works after rmdir...\n");
|
||||
startup();
|
||||
killdir();
|
||||
printf("Checking if creating files works after rmdir...\n");
|
||||
startup();
|
||||
killdir();
|
||||
|
||||
fd = open("newfile", O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd<0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "%s", buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnx("newfile: creating files after rmdir works");
|
||||
warnx("(this is only ok if the space gets reclaimed)");
|
||||
fd = open("newfile", O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "%s", buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
warnx("newfile: creating files after rmdir works");
|
||||
warnx("(this is only ok if the space gets reclaimed)");
|
||||
|
||||
/*
|
||||
* Waste a bunch of space so we'll be able to tell
|
||||
*/
|
||||
memset(buf, 'J', sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
}
|
||||
/*
|
||||
* Waste a bunch of space so we'll be able to tell
|
||||
*/
|
||||
memset(buf, 'J', sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
write(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
finish();
|
||||
finish();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now try to create directories.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
test5(void)
|
||||
{
|
||||
printf("Checking if creating subdirs works after rmdir...\n");
|
||||
startup();
|
||||
killdir();
|
||||
static void test5(void) {
|
||||
printf("Checking if creating subdirs works after rmdir...\n");
|
||||
startup();
|
||||
killdir();
|
||||
|
||||
if (mkdir("newdir", 0775)<0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "mkdir in removed dir");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnx("newfile: creating directories after rmdir works");
|
||||
warnx("(this is only ok if the space gets reclaimed)");
|
||||
if (mkdir("newdir", 0775) < 0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "mkdir in removed dir");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
warnx("newfile: creating directories after rmdir works");
|
||||
warnx("(this is only ok if the space gets reclaimed)");
|
||||
|
||||
/*
|
||||
* Waste a bunch of space so we'll be able to tell
|
||||
*/
|
||||
mkdir("newdir/t0", 0775);
|
||||
mkdir("newdir/t1", 0775);
|
||||
mkdir("newdir/t2", 0775);
|
||||
mkdir("newdir/t3", 0775);
|
||||
mkdir("newdir/t4", 0775);
|
||||
mkdir("newdir/t5", 0775);
|
||||
}
|
||||
/*
|
||||
* Waste a bunch of space so we'll be able to tell
|
||||
*/
|
||||
mkdir("newdir/t0", 0775);
|
||||
mkdir("newdir/t1", 0775);
|
||||
mkdir("newdir/t2", 0775);
|
||||
mkdir("newdir/t3", 0775);
|
||||
mkdir("newdir/t4", 0775);
|
||||
mkdir("newdir/t5", 0775);
|
||||
}
|
||||
|
||||
finish();
|
||||
finish();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now try listing the directory.
|
||||
*/
|
||||
static
|
||||
void
|
||||
test6(void)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
int fd, len;
|
||||
static void test6(void) {
|
||||
char buf[PATH_MAX];
|
||||
int fd, len;
|
||||
|
||||
printf("Now trying to list the directory...\n");
|
||||
startup();
|
||||
fd = open(".", O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, ".: open");
|
||||
}
|
||||
killdir();
|
||||
printf("Now trying to list the directory...\n");
|
||||
startup();
|
||||
fd = open(".", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, ".: open");
|
||||
}
|
||||
killdir();
|
||||
|
||||
while ((len = getdirentry(fd, buf, sizeof(buf)-1))>0) {
|
||||
if ((unsigned)len >= sizeof(buf)-1) {
|
||||
errx(1, ".: getdirentry: returned invalid length");
|
||||
}
|
||||
buf[len] = 0;
|
||||
if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
|
||||
/* these are allowed to appear */
|
||||
continue;
|
||||
}
|
||||
errx(1, ".: getdirentry: returned unexpected name %s", buf);
|
||||
}
|
||||
if (len==0) {
|
||||
/* EOF - ok */
|
||||
}
|
||||
else { /* len < 0 */
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
break;
|
||||
default:
|
||||
err(1, ".: getdirentry");
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((len = getdirentry(fd, buf, sizeof(buf) - 1)) > 0) {
|
||||
if ((unsigned)len >= sizeof(buf) - 1) {
|
||||
errx(1, ".: getdirentry: returned invalid length");
|
||||
}
|
||||
buf[len] = 0;
|
||||
if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
|
||||
/* these are allowed to appear */
|
||||
continue;
|
||||
}
|
||||
errx(1, ".: getdirentry: returned unexpected name %s", buf);
|
||||
}
|
||||
if (len == 0) {
|
||||
/* EOF - ok */
|
||||
} else { /* len < 0 */
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
break;
|
||||
default:
|
||||
err(1, ".: getdirentry");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
finish();
|
||||
finish();
|
||||
|
||||
/* close *after* leaving, just for excitement */
|
||||
if (close(fd)<0) {
|
||||
err(1, "removed %s: close", testdir);
|
||||
}
|
||||
/* close *after* leaving, just for excitement */
|
||||
if (close(fd) < 0) {
|
||||
err(1, "removed %s: close", testdir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try getcwd.
|
||||
*/
|
||||
static
|
||||
void
|
||||
test7(void)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
static void test7(void) {
|
||||
char buf[PATH_MAX];
|
||||
|
||||
startup();
|
||||
killdir();
|
||||
if (getcwd(buf, sizeof(buf))==NULL) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "getcwd after removing %s", testdir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
errx(1, "getcwd after removing %s: succeeded (got %s)",
|
||||
testdir, buf);
|
||||
}
|
||||
startup();
|
||||
killdir();
|
||||
if (getcwd(buf, sizeof(buf)) == NULL) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case EIO:
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
err(1, "getcwd after removing %s", testdir);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
errx(1, "getcwd after removing %s: succeeded (got %s)", testdir, buf);
|
||||
}
|
||||
|
||||
finish();
|
||||
finish();
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
int main(void) {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
|
||||
printf("Whew... survived.\n");
|
||||
return 0;
|
||||
printf("Whew... survived.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,121 +43,110 @@
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
|
||||
#define TEST "rmdata"
|
||||
#define TESTDATA "I wish I was a headlight. -- Jerry Garcia"
|
||||
#define TESTLEN (sizeof(TESTDATA)-1)
|
||||
#define TEST "rmdata"
|
||||
#define TESTDATA "I wish I was a headlight. -- Jerry Garcia"
|
||||
#define TESTLEN (sizeof(TESTDATA) - 1)
|
||||
|
||||
static
|
||||
void
|
||||
dorm(int fd)
|
||||
{
|
||||
/*
|
||||
* This used to spawn a copy of /bin/rm, but that's silly.
|
||||
* However, we will do the remove() from a subprocess, so
|
||||
* that various kinds of improper hacks to make this test
|
||||
* run won't work.
|
||||
*
|
||||
* Close the file in the subprocess, for similar reasons.
|
||||
*/
|
||||
static void dorm(int fd) {
|
||||
/*
|
||||
* This used to spawn a copy of /bin/rm, but that's silly.
|
||||
* However, we will do the remove() from a subprocess, so
|
||||
* that various kinds of improper hacks to make this test
|
||||
* run won't work.
|
||||
*
|
||||
* Close the file in the subprocess, for similar reasons.
|
||||
*/
|
||||
|
||||
pid_t pid;
|
||||
int status;
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (pid==0) {
|
||||
/* child process */
|
||||
close(fd);
|
||||
if (remove(TEST)) {
|
||||
err(1, "%s: remove", TEST);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
/* parent process */
|
||||
if (waitpid(pid, &status, 0)<0) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
warn("child process exited with signal %d", WTERMSIG(status));
|
||||
}
|
||||
else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("child process exited with code %d",WEXITSTATUS(status));
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* child process */
|
||||
close(fd);
|
||||
if (remove(TEST)) {
|
||||
err(1, "%s: remove", TEST);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
/* parent process */
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
err(1, "waitpid");
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warn("child process exited with signal %d", WTERMSIG(status));
|
||||
} else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("child process exited with code %d", WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
same(const char *a, const char *b, int len)
|
||||
{
|
||||
while (len-- > 0) {
|
||||
if (*a++ != *b++) return 0;
|
||||
}
|
||||
return 1;
|
||||
static int same(const char *a, const char *b, int len) {
|
||||
while (len-- > 0) {
|
||||
if (*a++ != *b++)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int file, len;
|
||||
char buf[TESTLEN];
|
||||
int main(void) {
|
||||
int file, len;
|
||||
char buf[TESTLEN];
|
||||
|
||||
/* create test data file */
|
||||
file = open(TEST, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
write(file, TESTDATA, TESTLEN);
|
||||
close(file);
|
||||
/* create test data file */
|
||||
file = open(TEST, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
write(file, TESTDATA, TESTLEN);
|
||||
close(file);
|
||||
|
||||
/* make sure the data is there */
|
||||
file = open(TEST, O_RDONLY);
|
||||
len = read(file, buf, TESTLEN);
|
||||
if (len < 0) {
|
||||
warn("read: before deletion");
|
||||
}
|
||||
else if (len < (int)TESTLEN) {
|
||||
warnx("read: before deletion: short count %d", len);
|
||||
}
|
||||
if (!same(buf, TESTDATA, TESTLEN)) {
|
||||
errx(1, "Failed: data read back was not the same");
|
||||
}
|
||||
/* make sure the data is there */
|
||||
file = open(TEST, O_RDONLY);
|
||||
len = read(file, buf, TESTLEN);
|
||||
if (len < 0) {
|
||||
warn("read: before deletion");
|
||||
} else if (len < (int)TESTLEN) {
|
||||
warnx("read: before deletion: short count %d", len);
|
||||
}
|
||||
if (!same(buf, TESTDATA, TESTLEN)) {
|
||||
errx(1, "Failed: data read back was not the same");
|
||||
}
|
||||
|
||||
/* rewind the file */
|
||||
if (lseek(file, 0, SEEK_SET)) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
/* rewind the file */
|
||||
if (lseek(file, 0, SEEK_SET)) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
|
||||
/* now spawn our killer and wait for it to do its work */
|
||||
dorm(file);
|
||||
/* now spawn our killer and wait for it to do its work */
|
||||
dorm(file);
|
||||
|
||||
/* we should be still able to read the data */
|
||||
memset(buf, '\0', TESTLEN);
|
||||
len = read(file, buf, TESTLEN);
|
||||
if (len < 0) {
|
||||
warn("read: after deletion");
|
||||
}
|
||||
else if (len < (int)TESTLEN) {
|
||||
warnx("read: after deletion: short count %d", len);
|
||||
}
|
||||
/* we should be still able to read the data */
|
||||
memset(buf, '\0', TESTLEN);
|
||||
len = read(file, buf, TESTLEN);
|
||||
if (len < 0) {
|
||||
warn("read: after deletion");
|
||||
} else if (len < (int)TESTLEN) {
|
||||
warnx("read: after deletion: short count %d", len);
|
||||
}
|
||||
|
||||
if (!same(buf, TESTDATA, TESTLEN)) {
|
||||
errx(1, "Failed: data read after deletion was not the same");
|
||||
}
|
||||
if (!same(buf, TESTDATA, TESTLEN)) {
|
||||
errx(1, "Failed: data read after deletion was not the same");
|
||||
}
|
||||
|
||||
/* ok, close the file and it should go away */
|
||||
close(file);
|
||||
/* ok, close the file and it should go away */
|
||||
close(file);
|
||||
|
||||
/* try to open it again */
|
||||
file = open(TEST, O_RDONLY);
|
||||
if (file >= 0) {
|
||||
close(file);
|
||||
errx(1, "Failed: the file could still be opened");
|
||||
}
|
||||
/* try to open it again */
|
||||
file = open(TEST, O_RDONLY);
|
||||
if (file >= 0) {
|
||||
close(file);
|
||||
errx(1, "Failed: the file could still be opened");
|
||||
}
|
||||
|
||||
if (errno!=ENOENT) {
|
||||
err(1, "Unexpected error reopening the file");
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
err(1, "Unexpected error reopening the file");
|
||||
}
|
||||
|
||||
printf("Succeeded!\n");
|
||||
printf("Succeeded!\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,46 +40,40 @@
|
||||
/*
|
||||
* comparison functions for qsort
|
||||
*/
|
||||
static
|
||||
int
|
||||
uintcmp(const void *av, const void *bv)
|
||||
{
|
||||
unsigned a = *(const unsigned *)av;
|
||||
unsigned b = *(const unsigned *)bv;
|
||||
static int uintcmp(const void *av, const void *bv) {
|
||||
unsigned a = *(const unsigned *)av;
|
||||
unsigned b = *(const unsigned *)bv;
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
altcmp(const void *av, const void *bv)
|
||||
{
|
||||
unsigned a = *(const unsigned *)av;
|
||||
unsigned b = *(const unsigned *)bv;
|
||||
unsigned ax = (a & 0xffff0000) >> 16;
|
||||
unsigned ay = a & 0xffff;
|
||||
unsigned bx = (b & 0xffff0000) >> 16;
|
||||
unsigned by = b & 0xffff;
|
||||
static int altcmp(const void *av, const void *bv) {
|
||||
unsigned a = *(const unsigned *)av;
|
||||
unsigned b = *(const unsigned *)bv;
|
||||
unsigned ax = (a & 0xffff0000) >> 16;
|
||||
unsigned ay = a & 0xffff;
|
||||
unsigned bx = (b & 0xffff0000) >> 16;
|
||||
unsigned by = b & 0xffff;
|
||||
|
||||
if (ax < bx) {
|
||||
return 1;
|
||||
}
|
||||
if (ax > bx) {
|
||||
return -1;
|
||||
}
|
||||
if (ay < by) {
|
||||
return -1;
|
||||
}
|
||||
if (ay > by) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if (ax < bx) {
|
||||
return 1;
|
||||
}
|
||||
if (ax > bx) {
|
||||
return -1;
|
||||
}
|
||||
if (ay < by) {
|
||||
return -1;
|
||||
}
|
||||
if (ay > by) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -104,35 +98,29 @@ shuffle(unsigned *p, unsigned n)
|
||||
/*
|
||||
* Compute first differences.
|
||||
*/
|
||||
static
|
||||
void
|
||||
diffs(unsigned *p, unsigned n)
|
||||
{
|
||||
unsigned p0;
|
||||
unsigned i;
|
||||
static void diffs(unsigned *p, unsigned n) {
|
||||
unsigned p0;
|
||||
unsigned i;
|
||||
|
||||
p0 = p[0];
|
||||
p0 = p[0];
|
||||
|
||||
for (i=0; i<n-1; i++) {
|
||||
p[i] = p[i] - p[i+1];
|
||||
}
|
||||
p[n-1] = p[n-1] - p0;
|
||||
for (i = 0; i < n - 1; i++) {
|
||||
p[i] = p[i] - p[i + 1];
|
||||
}
|
||||
p[n - 1] = p[n - 1] - p0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take the sum.
|
||||
*/
|
||||
static
|
||||
unsigned
|
||||
sum(const unsigned *p, unsigned n)
|
||||
{
|
||||
unsigned t, i;
|
||||
static unsigned sum(const unsigned *p, unsigned n) {
|
||||
unsigned t, i;
|
||||
|
||||
t = 0;
|
||||
for (i=0; i<n; i++) {
|
||||
t += p[i];
|
||||
}
|
||||
return t;
|
||||
t = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
t += p[i];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -140,66 +128,64 @@ sum(const unsigned *p, unsigned n)
|
||||
*
|
||||
* Note that this won't work until you have a VM system.
|
||||
*/
|
||||
void
|
||||
grind(unsigned groupid, unsigned id)
|
||||
{
|
||||
unsigned *p;
|
||||
unsigned i, n, s;
|
||||
void grind(unsigned groupid, unsigned id) {
|
||||
unsigned *p;
|
||||
unsigned i, n, s;
|
||||
|
||||
(void)groupid;
|
||||
(void)groupid;
|
||||
|
||||
waitstart();
|
||||
waitstart();
|
||||
|
||||
/* each grind task uses 768K */
|
||||
n = (768*1024) / sizeof(*p);
|
||||
p = malloc(n * sizeof(*p));
|
||||
if (p == NULL) {
|
||||
if (errno == ENOSYS) {
|
||||
/*
|
||||
* If we don't have sbrk, just bail out with
|
||||
* "success" instead of failing the whole
|
||||
* workload.
|
||||
*/
|
||||
errx(0, "grind: sbrk/malloc not implemented");
|
||||
}
|
||||
err(1, "malloc");
|
||||
}
|
||||
/* each grind task uses 768K */
|
||||
n = (768 * 1024) / sizeof(*p);
|
||||
p = malloc(n * sizeof(*p));
|
||||
if (p == NULL) {
|
||||
if (errno == ENOSYS) {
|
||||
/*
|
||||
* If we don't have sbrk, just bail out with
|
||||
* "success" instead of failing the whole
|
||||
* workload.
|
||||
*/
|
||||
errx(0, "grind: sbrk/malloc not implemented");
|
||||
}
|
||||
err(1, "malloc");
|
||||
}
|
||||
|
||||
/* First, get some random integers. */
|
||||
warnx("grind %u: seeding", id);
|
||||
srandom(1753);
|
||||
for (i=0; i<n; i++) {
|
||||
p[i] = random();
|
||||
}
|
||||
/* First, get some random integers. */
|
||||
warnx("grind %u: seeding", id);
|
||||
srandom(1753);
|
||||
for (i = 0; i < n; i++) {
|
||||
p[i] = random();
|
||||
}
|
||||
|
||||
/* Now sort them. */
|
||||
warnx("grind %u: sorting", id);
|
||||
qsort(p, n, sizeof(p[0]), uintcmp);
|
||||
/* Now sort them. */
|
||||
warnx("grind %u: sorting", id);
|
||||
qsort(p, n, sizeof(p[0]), uintcmp);
|
||||
|
||||
/* Sort by a different comparison. */
|
||||
warnx("grind %u: sorting alternately", id);
|
||||
qsort(p, n, sizeof(p[0]), altcmp);
|
||||
/* Sort by a different comparison. */
|
||||
warnx("grind %u: sorting alternately", id);
|
||||
qsort(p, n, sizeof(p[0]), altcmp);
|
||||
|
||||
/* Take the sum. */
|
||||
warnx("grind %u: summing", id);
|
||||
s = sum(p, n);
|
||||
warnx("grind %u: sum is %u (should be %u)", id, s, RIGHT);
|
||||
if (s != RIGHT) {
|
||||
errx(1, "grind %u FAILED", id);
|
||||
}
|
||||
/* Take the sum. */
|
||||
warnx("grind %u: summing", id);
|
||||
s = sum(p, n);
|
||||
warnx("grind %u: sum is %u (should be %u)", id, s, RIGHT);
|
||||
if (s != RIGHT) {
|
||||
errx(1, "grind %u FAILED", id);
|
||||
}
|
||||
|
||||
/* Take first differences. */
|
||||
warnx("grind %u: first differences", id);
|
||||
diffs(p, n);
|
||||
/* Take first differences. */
|
||||
warnx("grind %u: first differences", id);
|
||||
diffs(p, n);
|
||||
|
||||
/* Sort. */
|
||||
warnx("grind %u: sorting", id);
|
||||
qsort(p, n, sizeof(p[0]), uintcmp);
|
||||
/* Sort. */
|
||||
warnx("grind %u: sorting", id);
|
||||
qsort(p, n, sizeof(p[0]), uintcmp);
|
||||
|
||||
warnx("grind %u: summing", id);
|
||||
s = sum(p, n);
|
||||
warnx("grind %u: sum is %u (should be 0)", id, s);
|
||||
if (s != 0) {
|
||||
errx(1, "grind %u FAILED", id);
|
||||
}
|
||||
warnx("grind %u: summing", id);
|
||||
s = sum(p, n);
|
||||
warnx("grind %u: sum is %u (should be 0)", id, s);
|
||||
if (s != 0) {
|
||||
errx(1, "grind %u FAILED", id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,91 +48,81 @@ struct usem startsem;
|
||||
/*
|
||||
* Task hook function that does nothing.
|
||||
*/
|
||||
static
|
||||
void
|
||||
nop(unsigned groupid, unsigned count)
|
||||
{
|
||||
(void)groupid;
|
||||
(void)count;
|
||||
static void nop(unsigned groupid, unsigned count) {
|
||||
(void)groupid;
|
||||
(void)count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for wait.
|
||||
*/
|
||||
static
|
||||
unsigned
|
||||
dowait(pid_t pid)
|
||||
{
|
||||
int r;
|
||||
int status;
|
||||
static unsigned dowait(pid_t pid) {
|
||||
int r;
|
||||
int status;
|
||||
|
||||
r = waitpid(pid, &status, 0);
|
||||
if (r < 0) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d signal %d", pid, WTERMSIG(status));
|
||||
return 1;
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d exit %d", pid, WEXITSTATUS(status));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
r = waitpid(pid, &status, 0);
|
||||
if (r < 0) {
|
||||
err(1, "waitpid");
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d signal %d", pid, WTERMSIG(status));
|
||||
return 1;
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d exit %d", pid, WEXITSTATUS(status));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do a task group: fork the processes, then wait for them.
|
||||
*/
|
||||
static
|
||||
void
|
||||
runtaskgroup(unsigned count,
|
||||
void (*prep)(unsigned, unsigned),
|
||||
void (*task)(unsigned, unsigned),
|
||||
void (*cleanup)(unsigned, unsigned),
|
||||
unsigned groupid)
|
||||
{
|
||||
pid_t mypids[count];
|
||||
unsigned i;
|
||||
unsigned failures = 0;
|
||||
time_t secs;
|
||||
unsigned long nsecs;
|
||||
static void runtaskgroup(unsigned count, void (*prep)(unsigned, unsigned),
|
||||
void (*task)(unsigned, unsigned),
|
||||
void (*cleanup)(unsigned, unsigned),
|
||||
unsigned groupid) {
|
||||
pid_t mypids[count];
|
||||
unsigned i;
|
||||
unsigned failures = 0;
|
||||
time_t secs;
|
||||
unsigned long nsecs;
|
||||
|
||||
prep(groupid, count);
|
||||
prep(groupid, count);
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
mypids[i] = fork();
|
||||
if (mypids[i] < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (mypids[i] == 0) {
|
||||
/* child (of second fork) */
|
||||
task(groupid, i);
|
||||
exit(0);
|
||||
}
|
||||
/* parent (of second fork) - continue */
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
mypids[i] = fork();
|
||||
if (mypids[i] < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (mypids[i] == 0) {
|
||||
/* child (of second fork) */
|
||||
task(groupid, i);
|
||||
exit(0);
|
||||
}
|
||||
/* parent (of second fork) - continue */
|
||||
}
|
||||
|
||||
/*
|
||||
* now wait for the task to finish
|
||||
*/
|
||||
/*
|
||||
* now wait for the task to finish
|
||||
*/
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
failures += dowait(mypids[i]);
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
failures += dowait(mypids[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the end time.
|
||||
*/
|
||||
/*
|
||||
* Store the end time.
|
||||
*/
|
||||
|
||||
__time(&secs, &nsecs);
|
||||
openresultsfile(O_WRONLY);
|
||||
putresult(groupid, secs, nsecs);
|
||||
closeresultsfile();
|
||||
__time(&secs, &nsecs);
|
||||
openresultsfile(O_WRONLY);
|
||||
putresult(groupid, secs, nsecs);
|
||||
closeresultsfile();
|
||||
|
||||
cleanup(groupid, count);
|
||||
cleanup(groupid, count);
|
||||
|
||||
exit(failures ? 1 : 0);
|
||||
exit(failures ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -143,177 +133,150 @@ runtaskgroup(unsigned count,
|
||||
* get timing results even on kernels that don't support waitpid with
|
||||
* WNOHANG.
|
||||
*/
|
||||
static
|
||||
void
|
||||
forkem(unsigned count,
|
||||
void (*prep)(unsigned, unsigned),
|
||||
void (*task)(unsigned, unsigned),
|
||||
void (*cleanup)(unsigned, unsigned),
|
||||
unsigned groupid,
|
||||
pid_t *retpid)
|
||||
{
|
||||
*retpid = fork();
|
||||
if (*retpid < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (*retpid == 0) {
|
||||
/* child */
|
||||
runtaskgroup(count, prep, task, cleanup, groupid);
|
||||
}
|
||||
/* parent -- just return */
|
||||
static void forkem(unsigned count, void (*prep)(unsigned, unsigned),
|
||||
void (*task)(unsigned, unsigned),
|
||||
void (*cleanup)(unsigned, unsigned), unsigned groupid,
|
||||
pid_t *retpid) {
|
||||
*retpid = fork();
|
||||
if (*retpid < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (*retpid == 0) {
|
||||
/* child */
|
||||
runtaskgroup(count, prep, task, cleanup, groupid);
|
||||
}
|
||||
/* parent -- just return */
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the task group directors to exit.
|
||||
*/
|
||||
static
|
||||
void
|
||||
waitall(pid_t *pids, unsigned numpids)
|
||||
{
|
||||
unsigned failures = 0;
|
||||
unsigned i;
|
||||
static void waitall(pid_t *pids, unsigned numpids) {
|
||||
unsigned failures = 0;
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<numpids; i++) {
|
||||
failures += dowait(pids[i]);
|
||||
}
|
||||
if (failures) {
|
||||
errx(1, "TEST FAILURE: one or more subprocesses broke");
|
||||
}
|
||||
for (i = 0; i < numpids; i++) {
|
||||
failures += dowait(pids[i]);
|
||||
}
|
||||
if (failures) {
|
||||
errx(1, "TEST FAILURE: one or more subprocesses broke");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch, compute, and print the timing for one task group.
|
||||
*/
|
||||
static
|
||||
void
|
||||
calcresult(unsigned groupid, time_t startsecs, unsigned long startnsecs,
|
||||
char *buf, size_t bufmax)
|
||||
{
|
||||
time_t secs;
|
||||
unsigned long nsecs;
|
||||
static void calcresult(unsigned groupid, time_t startsecs,
|
||||
unsigned long startnsecs, char *buf, size_t bufmax) {
|
||||
time_t secs;
|
||||
unsigned long nsecs;
|
||||
|
||||
getresult(groupid, &secs, &nsecs);
|
||||
getresult(groupid, &secs, &nsecs);
|
||||
|
||||
/* secs.nsecs -= startsecs.startnsecs */
|
||||
if (nsecs < startnsecs) {
|
||||
nsecs += 1000000000;
|
||||
secs--;
|
||||
}
|
||||
nsecs -= startnsecs;
|
||||
secs -= startsecs;
|
||||
snprintf(buf, bufmax, "%lld.%09lu", (long long)secs, nsecs);
|
||||
/* secs.nsecs -= startsecs.startnsecs */
|
||||
if (nsecs < startnsecs) {
|
||||
nsecs += 1000000000;
|
||||
secs--;
|
||||
}
|
||||
nsecs -= startnsecs;
|
||||
secs -= startsecs;
|
||||
snprintf(buf, bufmax, "%lld.%09lu", (long long)secs, nsecs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used by the tasks to wait to start.
|
||||
*/
|
||||
void
|
||||
waitstart(void)
|
||||
{
|
||||
usem_open(&startsem);
|
||||
P(&startsem);
|
||||
usem_close(&startsem);
|
||||
void waitstart(void) {
|
||||
usem_open(&startsem);
|
||||
P(&startsem);
|
||||
usem_close(&startsem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the whole workload.
|
||||
*/
|
||||
static
|
||||
void
|
||||
runit(unsigned numthinkers, unsigned numgrinders,
|
||||
unsigned numponggroups, unsigned ponggroupsize)
|
||||
{
|
||||
pid_t pids[numponggroups + 2];
|
||||
time_t startsecs;
|
||||
unsigned long startnsecs;
|
||||
char buf[32];
|
||||
unsigned i;
|
||||
static void runit(unsigned numthinkers, unsigned numgrinders,
|
||||
unsigned numponggroups, unsigned ponggroupsize) {
|
||||
pid_t pids[numponggroups + 2];
|
||||
time_t startsecs;
|
||||
unsigned long startnsecs;
|
||||
char buf[32];
|
||||
unsigned i;
|
||||
|
||||
printf("Running with %u thinkers, %u grinders, and %u pong groups "
|
||||
"of size %u each.\n", numthinkers, numgrinders, numponggroups,
|
||||
ponggroupsize);
|
||||
printf("Running with %u thinkers, %u grinders, and %u pong groups "
|
||||
"of size %u each.\n",
|
||||
numthinkers, numgrinders, numponggroups, ponggroupsize);
|
||||
|
||||
usem_init(&startsem, STARTSEM);
|
||||
createresultsfile();
|
||||
forkem(numthinkers, nop, think, nop, 0, &pids[0]);
|
||||
forkem(numgrinders, nop, grind, nop, 1, &pids[1]);
|
||||
for (i=0; i<numponggroups; i++) {
|
||||
forkem(ponggroupsize, pong_prep, pong, pong_cleanup, i+2,
|
||||
&pids[i+2]);
|
||||
}
|
||||
usem_open(&startsem);
|
||||
printf("Forking done; starting the workload.\n");
|
||||
__time(&startsecs, &startnsecs);
|
||||
Vn(&startsem, numthinkers + numgrinders +
|
||||
numponggroups * ponggroupsize);
|
||||
waitall(pids, numponggroups + 2);
|
||||
usem_close(&startsem);
|
||||
usem_cleanup(&startsem);
|
||||
usem_init(&startsem, STARTSEM);
|
||||
createresultsfile();
|
||||
forkem(numthinkers, nop, think, nop, 0, &pids[0]);
|
||||
forkem(numgrinders, nop, grind, nop, 1, &pids[1]);
|
||||
for (i = 0; i < numponggroups; i++) {
|
||||
forkem(ponggroupsize, pong_prep, pong, pong_cleanup, i + 2, &pids[i + 2]);
|
||||
}
|
||||
usem_open(&startsem);
|
||||
printf("Forking done; starting the workload.\n");
|
||||
__time(&startsecs, &startnsecs);
|
||||
Vn(&startsem, numthinkers + numgrinders + numponggroups * ponggroupsize);
|
||||
waitall(pids, numponggroups + 2);
|
||||
usem_close(&startsem);
|
||||
usem_cleanup(&startsem);
|
||||
|
||||
openresultsfile(O_RDONLY);
|
||||
openresultsfile(O_RDONLY);
|
||||
|
||||
printf("--- Timings ---\n");
|
||||
if (numthinkers > 0) {
|
||||
calcresult(0, startsecs, startnsecs, buf, sizeof(buf));
|
||||
printf("Thinkers: %s\n", buf);
|
||||
}
|
||||
printf("--- Timings ---\n");
|
||||
if (numthinkers > 0) {
|
||||
calcresult(0, startsecs, startnsecs, buf, sizeof(buf));
|
||||
printf("Thinkers: %s\n", buf);
|
||||
}
|
||||
|
||||
if (numgrinders > 0) {
|
||||
calcresult(1, startsecs, startnsecs, buf, sizeof(buf));
|
||||
printf("Grinders: %s\n", buf);
|
||||
}
|
||||
if (numgrinders > 0) {
|
||||
calcresult(1, startsecs, startnsecs, buf, sizeof(buf));
|
||||
printf("Grinders: %s\n", buf);
|
||||
}
|
||||
|
||||
for (i=0; i<numponggroups; i++) {
|
||||
calcresult(i+2, startsecs, startnsecs, buf, sizeof(buf));
|
||||
printf("Pong group %u: %s\n", i, buf);
|
||||
}
|
||||
for (i = 0; i < numponggroups; i++) {
|
||||
calcresult(i + 2, startsecs, startnsecs, buf, sizeof(buf));
|
||||
printf("Pong group %u: %s\n", i, buf);
|
||||
}
|
||||
|
||||
closeresultsfile();
|
||||
destroyresultsfile();
|
||||
closeresultsfile();
|
||||
destroyresultsfile();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
usage(const char *av0)
|
||||
{
|
||||
warnx("Usage: %s [options]", av0);
|
||||
warnx(" [-t thinkers] set number of thinkers (default 2)");
|
||||
warnx(" [-g grinders] set number of grinders (default 0)");
|
||||
warnx(" [-p ponggroups] set number of pong groups (default 1)");
|
||||
warnx(" [-s ponggroupsize] set pong group size (default 6)");
|
||||
warnx("Thinkers are CPU bound; grinders are memory-bound;");
|
||||
warnx("pong groups are I/O bound.");
|
||||
exit(1);
|
||||
static void usage(const char *av0) {
|
||||
warnx("Usage: %s [options]", av0);
|
||||
warnx(" [-t thinkers] set number of thinkers (default 2)");
|
||||
warnx(" [-g grinders] set number of grinders (default 0)");
|
||||
warnx(" [-p ponggroups] set number of pong groups (default 1)");
|
||||
warnx(" [-s ponggroupsize] set pong group size (default 6)");
|
||||
warnx("Thinkers are CPU bound; grinders are memory-bound;");
|
||||
warnx("pong groups are I/O bound.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
unsigned numthinkers = 2;
|
||||
unsigned numgrinders = 0;
|
||||
unsigned numponggroups = 1;
|
||||
unsigned ponggroupsize = 6;
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned numthinkers = 2;
|
||||
unsigned numgrinders = 0;
|
||||
unsigned numponggroups = 1;
|
||||
unsigned ponggroupsize = 6;
|
||||
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i=1; i<argc; i++) {
|
||||
if (!strcmp(argv[i], "-t")) {
|
||||
numthinkers = atoi(argv[++i]);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-g")) {
|
||||
numgrinders = atoi(argv[++i]);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-p")) {
|
||||
numponggroups = atoi(argv[++i]);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-s")) {
|
||||
ponggroupsize = atoi(argv[++i]);
|
||||
}
|
||||
else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-t")) {
|
||||
numthinkers = atoi(argv[++i]);
|
||||
} else if (!strcmp(argv[i], "-g")) {
|
||||
numgrinders = atoi(argv[++i]);
|
||||
} else if (!strcmp(argv[i], "-p")) {
|
||||
numponggroups = atoi(argv[++i]);
|
||||
} else if (!strcmp(argv[i], "-s")) {
|
||||
ponggroupsize = atoi(argv[++i]);
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
runit(numthinkers, numgrinders, numponggroups, ponggroupsize);
|
||||
return 0;
|
||||
runit(numthinkers, numgrinders, numponggroups, ponggroupsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
#define MAXCOUNT 64
|
||||
#define PONGLOOPS 1000
|
||||
//#define VERBOSE_PONG
|
||||
// #define VERBOSE_PONG
|
||||
|
||||
static struct usem sems[MAXCOUNT];
|
||||
static unsigned nsems;
|
||||
@@ -55,31 +55,27 @@ static unsigned nsems;
|
||||
* that way each task process has its own file handles and they don't
|
||||
* interfere with each other if file handle locking isn't so great.
|
||||
*/
|
||||
void
|
||||
pong_prep(unsigned groupid, unsigned count)
|
||||
{
|
||||
unsigned i;
|
||||
void pong_prep(unsigned groupid, unsigned count) {
|
||||
unsigned i;
|
||||
|
||||
if (count > MAXCOUNT) {
|
||||
err(1, "pong: too many pongers -- recompile pong.c");
|
||||
}
|
||||
for (i=0; i<count; i++) {
|
||||
usem_init(&sems[i], "sem:pong-%u-%u", groupid, i);
|
||||
}
|
||||
nsems = count;
|
||||
if (count > MAXCOUNT) {
|
||||
err(1, "pong: too many pongers -- recompile pong.c");
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
usem_init(&sems[i], "sem:pong-%u-%u", groupid, i);
|
||||
}
|
||||
nsems = count;
|
||||
}
|
||||
|
||||
void
|
||||
pong_cleanup(unsigned groupid, unsigned count)
|
||||
{
|
||||
unsigned i;
|
||||
void pong_cleanup(unsigned groupid, unsigned count) {
|
||||
unsigned i;
|
||||
|
||||
assert(nsems == count);
|
||||
(void)groupid;
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
usem_cleanup(&sems[i]);
|
||||
}
|
||||
assert(nsems == count);
|
||||
(void)groupid;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
usem_cleanup(&sems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -87,36 +83,33 @@ pong_cleanup(unsigned groupid, unsigned count)
|
||||
* If we're id 0, don't wait the first go so things start, but do
|
||||
* wait the last go.
|
||||
*/
|
||||
static
|
||||
void
|
||||
pong_cyclic(unsigned id)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned nextid;
|
||||
static void pong_cyclic(unsigned id) {
|
||||
unsigned i;
|
||||
unsigned nextid;
|
||||
|
||||
nextid = (id + 1) % nsems;
|
||||
for (i=0; i<PONGLOOPS; i++) {
|
||||
if (i > 0 || id > 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
nextid = (id + 1) % nsems;
|
||||
for (i = 0; i < PONGLOOPS; i++) {
|
||||
if (i > 0 || id > 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
#ifdef VERBOSE_PONG
|
||||
printf(" %u", id);
|
||||
printf(" %u", id);
|
||||
#else
|
||||
if (nextid == 0 && i % 16 == 0) {
|
||||
putchar('.');
|
||||
}
|
||||
if (nextid == 0 && i % 16 == 0) {
|
||||
putchar('.');
|
||||
}
|
||||
#endif
|
||||
V(&sems[nextid]);
|
||||
}
|
||||
if (id == 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
V(&sems[nextid]);
|
||||
}
|
||||
if (id == 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
#ifdef VERBOSE_PONG
|
||||
putchar('\n');
|
||||
putchar('\n');
|
||||
#else
|
||||
if (nextid == 0) {
|
||||
putchar('\n');
|
||||
}
|
||||
if (nextid == 0) {
|
||||
putchar('\n');
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -124,88 +117,80 @@ pong_cyclic(unsigned id)
|
||||
* Pong back and forth. This runs the tasks with middle numbers more
|
||||
* often.
|
||||
*/
|
||||
static
|
||||
void
|
||||
pong_reciprocating(unsigned id)
|
||||
{
|
||||
unsigned i, n;
|
||||
unsigned nextfwd, nextback;
|
||||
unsigned gofwd = 1;
|
||||
static void pong_reciprocating(unsigned id) {
|
||||
unsigned i, n;
|
||||
unsigned nextfwd, nextback;
|
||||
unsigned gofwd = 1;
|
||||
|
||||
if (id == 0) {
|
||||
nextfwd = nextback = 1;
|
||||
n = PONGLOOPS;
|
||||
}
|
||||
else if (id == nsems - 1) {
|
||||
nextfwd = nextback = nsems - 2;
|
||||
n = PONGLOOPS;
|
||||
}
|
||||
else {
|
||||
nextfwd = id + 1;
|
||||
nextback = id - 1;
|
||||
n = PONGLOOPS * 2;
|
||||
}
|
||||
if (id == 0) {
|
||||
nextfwd = nextback = 1;
|
||||
n = PONGLOOPS;
|
||||
} else if (id == nsems - 1) {
|
||||
nextfwd = nextback = nsems - 2;
|
||||
n = PONGLOOPS;
|
||||
} else {
|
||||
nextfwd = id + 1;
|
||||
nextback = id - 1;
|
||||
n = PONGLOOPS * 2;
|
||||
}
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
if (i > 0 || id > 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
if (i > 0 || id > 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
#ifdef VERBOSE_PONG
|
||||
printf(" %u", id);
|
||||
printf(" %u", id);
|
||||
#else
|
||||
if (id == 0 && i % 16 == 0) {
|
||||
putchar('.');
|
||||
}
|
||||
if (id == 0 && i % 16 == 0) {
|
||||
putchar('.');
|
||||
}
|
||||
#endif
|
||||
if (gofwd) {
|
||||
V(&sems[nextfwd]);
|
||||
gofwd = 0;
|
||||
}
|
||||
else {
|
||||
V(&sems[nextback]);
|
||||
gofwd = 1;
|
||||
}
|
||||
}
|
||||
if (id == 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
if (gofwd) {
|
||||
V(&sems[nextfwd]);
|
||||
gofwd = 0;
|
||||
} else {
|
||||
V(&sems[nextback]);
|
||||
gofwd = 1;
|
||||
}
|
||||
}
|
||||
if (id == 0) {
|
||||
P(&sems[id]);
|
||||
}
|
||||
#ifdef VERBOSE_PONG
|
||||
putchar('\n');
|
||||
putchar('\n');
|
||||
#else
|
||||
if (id == 0) {
|
||||
putchar('\n');
|
||||
}
|
||||
if (id == 0) {
|
||||
putchar('\n');
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the pong thing.
|
||||
*/
|
||||
void
|
||||
pong(unsigned groupid, unsigned id)
|
||||
{
|
||||
unsigned idfwd, idback;
|
||||
void pong(unsigned groupid, unsigned id) {
|
||||
unsigned idfwd, idback;
|
||||
|
||||
(void)groupid;
|
||||
(void)groupid;
|
||||
|
||||
idfwd = (id + 1) % nsems;
|
||||
idback = (id + nsems - 1) % nsems;
|
||||
usem_open(&sems[id]);
|
||||
usem_open(&sems[idfwd]);
|
||||
usem_open(&sems[idback]);
|
||||
idfwd = (id + 1) % nsems;
|
||||
idback = (id + nsems - 1) % nsems;
|
||||
usem_open(&sems[id]);
|
||||
usem_open(&sems[idfwd]);
|
||||
usem_open(&sems[idback]);
|
||||
|
||||
waitstart();
|
||||
pong_cyclic(id);
|
||||
waitstart();
|
||||
pong_cyclic(id);
|
||||
#ifdef VERBOSE_PONG
|
||||
printf("--------------------------------\n");
|
||||
printf("--------------------------------\n");
|
||||
#endif
|
||||
pong_reciprocating(id);
|
||||
pong_reciprocating(id);
|
||||
#ifdef VERBOSE_PONG
|
||||
printf("--------------------------------\n");
|
||||
printf("--------------------------------\n");
|
||||
#endif
|
||||
pong_cyclic(id);
|
||||
pong_cyclic(id);
|
||||
|
||||
usem_close(&sems[id]);
|
||||
usem_close(&sems[idfwd]);
|
||||
usem_close(&sems[idback]);
|
||||
usem_close(&sems[id]);
|
||||
usem_close(&sems[idfwd]);
|
||||
usem_close(&sems[idback]);
|
||||
}
|
||||
|
||||
@@ -44,34 +44,30 @@ static int resultsfile = -1;
|
||||
* Create the file that the timing results are written to.
|
||||
* This is done first, in the main process.
|
||||
*/
|
||||
void
|
||||
createresultsfile(void)
|
||||
{
|
||||
int fd;
|
||||
void createresultsfile(void) {
|
||||
int fd;
|
||||
|
||||
assert(resultsfile == -1);
|
||||
assert(resultsfile == -1);
|
||||
|
||||
fd = open(RESULTSFILE, O_RDWR|O_CREAT|O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", RESULTSFILE);
|
||||
}
|
||||
if (close(fd) == -1) {
|
||||
warn("%s: close", RESULTSFILE);
|
||||
}
|
||||
fd = open(RESULTSFILE, O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", RESULTSFILE);
|
||||
}
|
||||
if (close(fd) == -1) {
|
||||
warn("%s: close", RESULTSFILE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the timing results file.
|
||||
* This is done last, in the main process.
|
||||
*/
|
||||
void
|
||||
destroyresultsfile(void)
|
||||
{
|
||||
if (remove(RESULTSFILE) == -1) {
|
||||
if (errno != ENOSYS) {
|
||||
warn("%s: remove", RESULTSFILE);
|
||||
}
|
||||
}
|
||||
void destroyresultsfile(void) {
|
||||
if (remove(RESULTSFILE) == -1) {
|
||||
if (errno != ENOSYS) {
|
||||
warn("%s: remove", RESULTSFILE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -80,90 +76,82 @@ destroyresultsfile(void)
|
||||
* then require extra semaphoring to coordinate...) and afterwards
|
||||
* done for reading in the main process.
|
||||
*/
|
||||
void
|
||||
openresultsfile(int openflags)
|
||||
{
|
||||
assert(openflags == O_RDONLY || openflags == O_WRONLY);
|
||||
assert(resultsfile == -1);
|
||||
void openresultsfile(int openflags) {
|
||||
assert(openflags == O_RDONLY || openflags == O_WRONLY);
|
||||
assert(resultsfile == -1);
|
||||
|
||||
resultsfile = open(RESULTSFILE, openflags, 0);
|
||||
if (resultsfile < 0) {
|
||||
err(1, "%s", RESULTSFILE);
|
||||
}
|
||||
resultsfile = open(RESULTSFILE, openflags, 0);
|
||||
if (resultsfile < 0) {
|
||||
err(1, "%s", RESULTSFILE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the timing results file.
|
||||
*/
|
||||
void
|
||||
closeresultsfile(void)
|
||||
{
|
||||
assert(resultsfile >= 0);
|
||||
void closeresultsfile(void) {
|
||||
assert(resultsfile >= 0);
|
||||
|
||||
if (close(resultsfile) == -1) {
|
||||
warn("%s: close", RESULTSFILE);
|
||||
}
|
||||
resultsfile = -1;
|
||||
if (close(resultsfile) == -1) {
|
||||
warn("%s: close", RESULTSFILE);
|
||||
}
|
||||
resultsfile = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a result into the timing results file.
|
||||
*/
|
||||
void
|
||||
putresult(unsigned groupid, time_t secs, unsigned long nsecs)
|
||||
{
|
||||
off_t pos;
|
||||
ssize_t r;
|
||||
void putresult(unsigned groupid, time_t secs, unsigned long nsecs) {
|
||||
off_t pos;
|
||||
ssize_t r;
|
||||
|
||||
assert(resultsfile >= 0);
|
||||
assert(resultsfile >= 0);
|
||||
|
||||
pos = groupid * (sizeof(secs) + sizeof(nsecs));
|
||||
if (lseek(resultsfile, pos, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek", RESULTSFILE);
|
||||
}
|
||||
r = write(resultsfile, &secs, sizeof(secs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: write (seconds)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(secs)) {
|
||||
errx(1, "%s: write (seconds): Short write", RESULTSFILE);
|
||||
}
|
||||
r = write(resultsfile, &nsecs, sizeof(nsecs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: write (nsecs)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(nsecs)) {
|
||||
errx(1, "%s: write (nsecs): Short write", RESULTSFILE);
|
||||
}
|
||||
pos = groupid * (sizeof(secs) + sizeof(nsecs));
|
||||
if (lseek(resultsfile, pos, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek", RESULTSFILE);
|
||||
}
|
||||
r = write(resultsfile, &secs, sizeof(secs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: write (seconds)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(secs)) {
|
||||
errx(1, "%s: write (seconds): Short write", RESULTSFILE);
|
||||
}
|
||||
r = write(resultsfile, &nsecs, sizeof(nsecs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: write (nsecs)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(nsecs)) {
|
||||
errx(1, "%s: write (nsecs): Short write", RESULTSFILE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a result from the timing results file.
|
||||
*/
|
||||
void
|
||||
getresult(unsigned groupid, time_t *secs, unsigned long *nsecs)
|
||||
{
|
||||
off_t pos;
|
||||
ssize_t r;
|
||||
void getresult(unsigned groupid, time_t *secs, unsigned long *nsecs) {
|
||||
off_t pos;
|
||||
ssize_t r;
|
||||
|
||||
assert(resultsfile >= 0);
|
||||
assert(resultsfile >= 0);
|
||||
|
||||
pos = groupid * (sizeof(*secs) + sizeof(*nsecs));
|
||||
if (lseek(resultsfile, pos, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek", RESULTSFILE);
|
||||
}
|
||||
r = read(resultsfile, secs, sizeof(*secs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: read (seconds)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(*secs)) {
|
||||
errx(1, "%s: read (seconds): Unexpected EOF", RESULTSFILE);
|
||||
}
|
||||
r = read(resultsfile, nsecs, sizeof(*nsecs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: read (nsecs)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(*nsecs)) {
|
||||
errx(1, "%s: read (nsecs): Unexpected EOF", RESULTSFILE);
|
||||
}
|
||||
pos = groupid * (sizeof(*secs) + sizeof(*nsecs));
|
||||
if (lseek(resultsfile, pos, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek", RESULTSFILE);
|
||||
}
|
||||
r = read(resultsfile, secs, sizeof(*secs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: read (seconds)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(*secs)) {
|
||||
errx(1, "%s: read (seconds): Unexpected EOF", RESULTSFILE);
|
||||
}
|
||||
r = read(resultsfile, nsecs, sizeof(*nsecs));
|
||||
if (r < 0) {
|
||||
err(1, "%s: read (nsecs)", RESULTSFILE);
|
||||
}
|
||||
if ((size_t)r < sizeof(*nsecs)) {
|
||||
errx(1, "%s: read (nsecs): Unexpected EOF", RESULTSFILE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,21 +35,19 @@
|
||||
*
|
||||
* All we do is loop.
|
||||
*/
|
||||
void
|
||||
think(unsigned groupid, unsigned id)
|
||||
{
|
||||
volatile unsigned long k, m;
|
||||
volatile unsigned i;
|
||||
void think(unsigned groupid, unsigned id) {
|
||||
volatile unsigned long k, m;
|
||||
volatile unsigned i;
|
||||
|
||||
(void)groupid;
|
||||
(void)id;
|
||||
(void)groupid;
|
||||
(void)id;
|
||||
|
||||
waitstart();
|
||||
waitstart();
|
||||
|
||||
k = 15;
|
||||
m = 7;
|
||||
k = 15;
|
||||
m = 7;
|
||||
#define LOOPCOUNT 35000000
|
||||
for (i=0; i<LOOPCOUNT; i++) {
|
||||
k += k*m;
|
||||
}
|
||||
for (i = 0; i < LOOPCOUNT; i++) {
|
||||
k += k * m;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,87 +41,65 @@
|
||||
|
||||
#include "usem.h"
|
||||
|
||||
void
|
||||
usem_init(struct usem *sem, const char *namefmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void usem_init(struct usem *sem, const char *namefmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, namefmt);
|
||||
vsnprintf(sem->name, sizeof(sem->name), namefmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, namefmt);
|
||||
vsnprintf(sem->name, sizeof(sem->name), namefmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
sem->fd = open(sem->name, O_RDWR|O_CREAT|O_TRUNC, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(sem->fd);
|
||||
sem->fd = -1;
|
||||
sem->fd = open(sem->name, O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(sem->fd);
|
||||
sem->fd = -1;
|
||||
}
|
||||
|
||||
void
|
||||
usem_open(struct usem *sem)
|
||||
{
|
||||
sem->fd = open(sem->name, O_RDWR);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
void usem_open(struct usem *sem) {
|
||||
sem->fd = open(sem->name, O_RDWR);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usem_close(struct usem *sem)
|
||||
{
|
||||
if (close(sem->fd) == -1) {
|
||||
warn("%s: close", sem->name);
|
||||
}
|
||||
void usem_close(struct usem *sem) {
|
||||
if (close(sem->fd) == -1) {
|
||||
warn("%s: close", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usem_cleanup(struct usem *sem)
|
||||
{
|
||||
(void)remove(sem->name);
|
||||
void usem_cleanup(struct usem *sem) { (void)remove(sem->name); }
|
||||
|
||||
void Pn(struct usem *sem, unsigned count) {
|
||||
ssize_t r;
|
||||
char c[count];
|
||||
|
||||
r = read(sem->fd, c, count);
|
||||
if (r < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
if ((size_t)r < count) {
|
||||
errx(1, "%s: read: unexpected EOF", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pn(struct usem *sem, unsigned count)
|
||||
{
|
||||
ssize_t r;
|
||||
char c[count];
|
||||
void P(struct usem *sem) { Pn(sem, 1); }
|
||||
|
||||
r = read(sem->fd, c, count);
|
||||
if (r < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
if ((size_t)r < count) {
|
||||
errx(1, "%s: read: unexpected EOF", sem->name);
|
||||
}
|
||||
void Vn(struct usem *sem, unsigned count) {
|
||||
ssize_t r;
|
||||
char c[count];
|
||||
|
||||
/* semfs does not use these values, but be conservative */
|
||||
memset(c, 0, count);
|
||||
|
||||
r = write(sem->fd, c, count);
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
if ((size_t)r < count) {
|
||||
errx(1, "%s: write: Short count", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
P(struct usem *sem)
|
||||
{
|
||||
Pn(sem, 1);
|
||||
}
|
||||
|
||||
void
|
||||
Vn(struct usem *sem, unsigned count)
|
||||
{
|
||||
ssize_t r;
|
||||
char c[count];
|
||||
|
||||
/* semfs does not use these values, but be conservative */
|
||||
memset(c, 0, count);
|
||||
|
||||
r = write(sem->fd, c, count);
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
if ((size_t)r < count) {
|
||||
errx(1, "%s: write: Short count", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
V(struct usem *sem)
|
||||
{
|
||||
Vn(sem, 1);
|
||||
}
|
||||
void V(struct usem *sem) { Vn(sem, 1); }
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
* Semaphore structure.
|
||||
*/
|
||||
struct usem {
|
||||
char name[32];
|
||||
int fd;
|
||||
char name[32];
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* XXX this should be in sys/cdefs.h */
|
||||
|
||||
@@ -41,8 +41,7 @@
|
||||
#include <err.h>
|
||||
|
||||
/* Larger than physical memory */
|
||||
#define SIZE (144*1024)
|
||||
|
||||
#define SIZE (144 * 1024)
|
||||
|
||||
/*
|
||||
* Quicksort.
|
||||
@@ -54,82 +53,69 @@
|
||||
* Also, quicksort has somewhat more interesting memory usage patterns.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
sort(int *arr, int size)
|
||||
{
|
||||
static int tmp[SIZE];
|
||||
int pivot, i, j, k;
|
||||
static void sort(int *arr, int size) {
|
||||
static int tmp[SIZE];
|
||||
int pivot, i, j, k;
|
||||
|
||||
if (size<2) {
|
||||
return;
|
||||
}
|
||||
if (size < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
pivot = size/2;
|
||||
sort(arr, pivot);
|
||||
sort(&arr[pivot], size-pivot);
|
||||
pivot = size / 2;
|
||||
sort(arr, pivot);
|
||||
sort(&arr[pivot], size - pivot);
|
||||
|
||||
i = 0;
|
||||
j = pivot;
|
||||
k = 0;
|
||||
while (i<pivot && j<size) {
|
||||
if (arr[i] < arr[j]) {
|
||||
tmp[k++] = arr[i++];
|
||||
}
|
||||
else {
|
||||
tmp[k++] = arr[j++];
|
||||
}
|
||||
}
|
||||
while (i<pivot) {
|
||||
tmp[k++] = arr[i++];
|
||||
}
|
||||
while (j<size) {
|
||||
tmp[k++] = arr[j++];
|
||||
}
|
||||
i = 0;
|
||||
j = pivot;
|
||||
k = 0;
|
||||
while (i < pivot && j < size) {
|
||||
if (arr[i] < arr[j]) {
|
||||
tmp[k++] = arr[i++];
|
||||
} else {
|
||||
tmp[k++] = arr[j++];
|
||||
}
|
||||
}
|
||||
while (i < pivot) {
|
||||
tmp[k++] = arr[i++];
|
||||
}
|
||||
while (j < size) {
|
||||
tmp[k++] = arr[j++];
|
||||
}
|
||||
|
||||
memcpy(arr, tmp, size*sizeof(int));
|
||||
memcpy(arr, tmp, size * sizeof(int));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static int A[SIZE];
|
||||
|
||||
static
|
||||
void
|
||||
initarray(void)
|
||||
{
|
||||
int i;
|
||||
static void initarray(void) {
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Initialize the array, with pseudo-random but deterministic contents.
|
||||
*/
|
||||
srandom(533);
|
||||
/*
|
||||
* Initialize the array, with pseudo-random but deterministic contents.
|
||||
*/
|
||||
srandom(533);
|
||||
|
||||
for (i = 0; i < SIZE; i++) {
|
||||
A[i] = random();
|
||||
}
|
||||
for (i = 0; i < SIZE; i++) {
|
||||
A[i] = random();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
check(void)
|
||||
{
|
||||
int i;
|
||||
static void check(void) {
|
||||
int i;
|
||||
|
||||
for (i=0; i<SIZE-1; i++) {
|
||||
if (A[i] > A[i+1]) {
|
||||
errx(1, "Failed: A[%d] is %d, A[%d] is %d",
|
||||
i, A[i], i+1, A[i+1]);
|
||||
}
|
||||
}
|
||||
warnx("Passed.");
|
||||
for (i = 0; i < SIZE - 1; i++) {
|
||||
if (A[i] > A[i + 1]) {
|
||||
errx(1, "Failed: A[%d] is %d, A[%d] is %d", i, A[i], i + 1, A[i + 1]);
|
||||
}
|
||||
}
|
||||
warnx("Passed.");
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
initarray();
|
||||
sort(A, SIZE);
|
||||
check();
|
||||
return 0;
|
||||
int main(void) {
|
||||
initarray();
|
||||
sort(A, SIZE);
|
||||
check();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -42,46 +42,43 @@
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *filename;
|
||||
int size;
|
||||
int fd;
|
||||
int r;
|
||||
char byte;
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *filename;
|
||||
int size;
|
||||
int fd;
|
||||
int r;
|
||||
char byte;
|
||||
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: sparsefile <filename> <size>");
|
||||
}
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: sparsefile <filename> <size>");
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
size = atoi(argv[2]);
|
||||
byte = '\n';
|
||||
filename = argv[1];
|
||||
size = atoi(argv[2]);
|
||||
byte = '\n';
|
||||
|
||||
if (size == 0) {
|
||||
err(1, "Sparse files of length zero are not meaningful");
|
||||
}
|
||||
if (size == 0) {
|
||||
err(1, "Sparse files of length zero are not meaningful");
|
||||
}
|
||||
|
||||
printf("Creating a sparse file of size %d\n", size);
|
||||
printf("Creating a sparse file of size %d\n", size);
|
||||
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", filename);
|
||||
}
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (fd < 0) {
|
||||
err(1, "%s: create", filename);
|
||||
}
|
||||
|
||||
if (lseek(fd, size-1, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek", filename);
|
||||
}
|
||||
r = write(fd, &byte, 1);
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", filename);
|
||||
}
|
||||
else if (r != 1) {
|
||||
errx(1, "%s: write: Unexpected result count %d", filename, r);
|
||||
}
|
||||
if (lseek(fd, size - 1, SEEK_SET) == -1) {
|
||||
err(1, "%s: lseek", filename);
|
||||
}
|
||||
r = write(fd, &byte, 1);
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", filename);
|
||||
} else if (r != 1) {
|
||||
errx(1, "%s: write: Unexpected result count %d", filename, r);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -47,35 +47,29 @@
|
||||
|
||||
char buffer[BUFSIZE];
|
||||
|
||||
static
|
||||
void
|
||||
tail(int file, off_t where, const char *filename)
|
||||
{
|
||||
int len;
|
||||
static void tail(int file, off_t where, const char *filename) {
|
||||
int len;
|
||||
|
||||
if (lseek(file, where, SEEK_SET)<0) {
|
||||
err(1, "%s", filename);
|
||||
}
|
||||
if (lseek(file, where, SEEK_SET) < 0) {
|
||||
err(1, "%s", filename);
|
||||
}
|
||||
|
||||
while ((len = read(file, buffer, sizeof(buffer))) > 0) {
|
||||
write(STDOUT_FILENO, buffer, len);
|
||||
}
|
||||
while ((len = read(file, buffer, sizeof(buffer))) > 0) {
|
||||
write(STDOUT_FILENO, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int file;
|
||||
int main(int argc, char **argv) {
|
||||
int file;
|
||||
|
||||
if (argc < 3) {
|
||||
errx(1, "Usage: tail <file> <location>");
|
||||
}
|
||||
file = open(argv[1], O_RDONLY);
|
||||
if (file < 0) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
tail(file, atoi(argv[2]), argv[1]);
|
||||
close(file);
|
||||
return 0;
|
||||
if (argc < 3) {
|
||||
errx(1, "Usage: tail <file> <location>");
|
||||
}
|
||||
file = open(argv[1], O_RDONLY);
|
||||
if (file < 0) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
tail(file, atoi(argv[2]), argv[1]);
|
||||
close(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,14 +42,14 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#define NEWLINE 012
|
||||
#define EMPTY 0
|
||||
#define X_PLAYER 1
|
||||
#define O_PLAYER 2
|
||||
#define X_MARKER 1
|
||||
#define O_MARKER 2
|
||||
#define DIM 3
|
||||
#define DIMCHAR "2"
|
||||
#define MAXSTRING 100
|
||||
#define EMPTY 0
|
||||
#define X_PLAYER 1
|
||||
#define O_PLAYER 2
|
||||
#define X_MARKER 1
|
||||
#define O_MARKER 2
|
||||
#define DIM 3
|
||||
#define DIMCHAR "2"
|
||||
#define MAXSTRING 100
|
||||
|
||||
typedef enum { FALSE, TRUE } bool;
|
||||
|
||||
@@ -58,7 +58,7 @@ bool ask_yesno(const char *msg);
|
||||
bool do_move(int player);
|
||||
void initialize_board(void);
|
||||
bool is_win(int x, int y);
|
||||
int read_string(char *buf, int length);
|
||||
int read_string(char *buf, int length);
|
||||
void print_board(void);
|
||||
void print_instructions(void);
|
||||
bool win_column(int y, int marker);
|
||||
@@ -67,7 +67,6 @@ bool win_diag_right(int x, int y, int marker);
|
||||
bool win_row(int x, int marker);
|
||||
bool Strcmp(const char *a, const char *b);
|
||||
|
||||
|
||||
/*
|
||||
* The board is gloabally defined.
|
||||
*/
|
||||
@@ -75,37 +74,35 @@ int board[DIM][DIM];
|
||||
|
||||
/* Console I/O routines */
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
bool win = FALSE;
|
||||
int move, max_moves;
|
||||
int player;
|
||||
int main(void) {
|
||||
bool win = FALSE;
|
||||
int move, max_moves;
|
||||
int player;
|
||||
|
||||
print_instructions();
|
||||
max_moves = DIM * DIM; /* Maximum number of moves in a game */
|
||||
print_instructions();
|
||||
max_moves = DIM * DIM; /* Maximum number of moves in a game */
|
||||
|
||||
while (TRUE) {
|
||||
initialize_board();
|
||||
for (move = 1; move <= max_moves; move++) {
|
||||
player = move % 2 == 0 ? 2 : 1;
|
||||
win = do_move(player);
|
||||
print_board();
|
||||
if (win) {
|
||||
printf("Player %d, you WON!\n\n", player);
|
||||
break; /* out of for loop */
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we got here by falling through the loop, then it is a
|
||||
* tie game.
|
||||
*/
|
||||
if (!win)
|
||||
printf("Tie Game!\n\n");
|
||||
if (!ask_yesno("Do you wish to play again?"))
|
||||
break; /* out of while loop */
|
||||
}
|
||||
return 0;
|
||||
while (TRUE) {
|
||||
initialize_board();
|
||||
for (move = 1; move <= max_moves; move++) {
|
||||
player = move % 2 == 0 ? 2 : 1;
|
||||
win = do_move(player);
|
||||
print_board();
|
||||
if (win) {
|
||||
printf("Player %d, you WON!\n\n", player);
|
||||
break; /* out of for loop */
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we got here by falling through the loop, then it is a
|
||||
* tie game.
|
||||
*/
|
||||
if (!win)
|
||||
printf("Tie Game!\n\n");
|
||||
if (!ask_yesno("Do you wish to play again?"))
|
||||
break; /* out of while loop */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -118,12 +115,10 @@ main(void)
|
||||
* Error
|
||||
* None
|
||||
*/
|
||||
void
|
||||
print_instructions(void)
|
||||
{
|
||||
printf("Welcome to tic-tac-toe!\n");
|
||||
printf("Player 1 always plays X and player 2 always play O\n");
|
||||
printf("Good luck!\n\n\n");
|
||||
void print_instructions(void) {
|
||||
printf("Welcome to tic-tac-toe!\n");
|
||||
printf("Player 1 always plays X and player 2 always play O\n");
|
||||
printf("Good luck!\n\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -139,25 +134,33 @@ void
|
||||
*/
|
||||
print_board(void)
|
||||
{
|
||||
int i, j;
|
||||
int i, j;
|
||||
|
||||
/* Print labels across the top */
|
||||
printf("\n 0 1 2\n");
|
||||
/* Print labels across the top */
|
||||
printf("\n 0 1 2\n");
|
||||
|
||||
for (i = 0; i < DIM; i++) {
|
||||
/* Print row labels */
|
||||
printf(" %d ", i);
|
||||
for (j = 0; j < DIM; j++) {
|
||||
switch (board[i][j]) {
|
||||
case EMPTY: printf(" "); break;
|
||||
case X_MARKER: printf(" X "); break;
|
||||
case O_MARKER: printf(" O "); break;
|
||||
default: printf("???"); break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < DIM; i++) {
|
||||
/* Print row labels */
|
||||
printf(" %d ", i);
|
||||
for (j = 0; j < DIM; j++) {
|
||||
switch (board[i][j]) {
|
||||
case EMPTY:
|
||||
printf(" ");
|
||||
break;
|
||||
case X_MARKER:
|
||||
printf(" X ");
|
||||
break;
|
||||
case O_MARKER:
|
||||
printf(" O ");
|
||||
break;
|
||||
default:
|
||||
printf("???");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -175,22 +178,20 @@ print_board(void)
|
||||
* Error
|
||||
* None
|
||||
*/
|
||||
bool
|
||||
ask_yesno(const char *msg)
|
||||
{
|
||||
char answer[MAXSTRING];
|
||||
bool ask_yesno(const char *msg) {
|
||||
char answer[MAXSTRING];
|
||||
|
||||
while (TRUE) {
|
||||
printf("%s [yes/no] ", msg);
|
||||
if (read_string(answer, MAXSTRING) < 0)
|
||||
return(FALSE);
|
||||
if (Strcmp(answer, "yes"))
|
||||
return(TRUE);
|
||||
else if (Strcmp(answer, "no"))
|
||||
return(FALSE);
|
||||
else
|
||||
printf("Please answer either yes or no\n");
|
||||
}
|
||||
while (TRUE) {
|
||||
printf("%s [yes/no] ", msg);
|
||||
if (read_string(answer, MAXSTRING) < 0)
|
||||
return (FALSE);
|
||||
if (Strcmp(answer, "yes"))
|
||||
return (TRUE);
|
||||
else if (Strcmp(answer, "no"))
|
||||
return (FALSE);
|
||||
else
|
||||
printf("Please answer either yes or no\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -209,47 +210,42 @@ ask_yesno(const char *msg)
|
||||
* Error
|
||||
* None
|
||||
*/
|
||||
bool
|
||||
do_move(int player)
|
||||
{
|
||||
int x, y;
|
||||
char answer[MAXSTRING];
|
||||
char cx;
|
||||
bool do_move(int player) {
|
||||
int x, y;
|
||||
char answer[MAXSTRING];
|
||||
char cx;
|
||||
|
||||
printf("Player %d (%c), your move\n", player,
|
||||
player == X_PLAYER ? 'X' : 'O');
|
||||
printf("Player %d (%c), your move\n", player, player == X_PLAYER ? 'X' : 'O');
|
||||
|
||||
while (TRUE) {
|
||||
printf("Which row [0-%d]: ", DIM-1);
|
||||
if (read_string(answer, MAXSTRING) < 0)
|
||||
return(FALSE);
|
||||
cx = answer[0];
|
||||
x = cx - '0';
|
||||
if (x < 0 || x >= DIM) {
|
||||
printf("Invalid row; must be >= 0 and < %d\n", DIM-1);
|
||||
continue;
|
||||
}
|
||||
printf("Which column [0-%d]: ", DIM-1);
|
||||
if (read_string(answer, MAXSTRING) < 0)
|
||||
return(FALSE);
|
||||
cx = answer[0];
|
||||
y = cx - '0';
|
||||
if (y < 0 || y >= DIM) {
|
||||
printf("Invalid column; must be >= 0 and < %d\n",
|
||||
DIM-1);
|
||||
continue;
|
||||
}
|
||||
while (TRUE) {
|
||||
printf("Which row [0-%d]: ", DIM - 1);
|
||||
if (read_string(answer, MAXSTRING) < 0)
|
||||
return (FALSE);
|
||||
cx = answer[0];
|
||||
x = cx - '0';
|
||||
if (x < 0 || x >= DIM) {
|
||||
printf("Invalid row; must be >= 0 and < %d\n", DIM - 1);
|
||||
continue;
|
||||
}
|
||||
printf("Which column [0-%d]: ", DIM - 1);
|
||||
if (read_string(answer, MAXSTRING) < 0)
|
||||
return (FALSE);
|
||||
cx = answer[0];
|
||||
y = cx - '0';
|
||||
if (y < 0 || y >= DIM) {
|
||||
printf("Invalid column; must be >= 0 and < %d\n", DIM - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (board[x][y] != EMPTY) {
|
||||
printf("That location is occupied; please try again\n");
|
||||
print_board();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
board[x][y] = player == X_PLAYER ? X_MARKER : O_MARKER;
|
||||
|
||||
return(is_win(x, y));
|
||||
if (board[x][y] != EMPTY) {
|
||||
printf("That location is occupied; please try again\n");
|
||||
print_board();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
board[x][y] = player == X_PLAYER ? X_MARKER : O_MARKER;
|
||||
|
||||
return (is_win(x, y));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -274,124 +270,106 @@ do_move(int player)
|
||||
* TRUE if player won
|
||||
* FALSE otherwise
|
||||
*/
|
||||
bool
|
||||
is_win(int x, int y)
|
||||
{
|
||||
int marker;
|
||||
bool is_win(int x, int y) {
|
||||
int marker;
|
||||
|
||||
marker = board[x][y];
|
||||
marker = board[x][y];
|
||||
|
||||
/*
|
||||
* Note that C "short circuit evaluation". As soon as any one
|
||||
* of these functions returns TRUE, we know that the expression
|
||||
* is true. Therefore, we can return TRUE without executing
|
||||
* any of the other routines.
|
||||
*/
|
||||
return(win_row(x, marker) || win_column(y, marker) ||
|
||||
win_diag_left(x, y, marker) || win_diag_right(x, y, marker));
|
||||
/*
|
||||
* Note that C "short circuit evaluation". As soon as any one
|
||||
* of these functions returns TRUE, we know that the expression
|
||||
* is true. Therefore, we can return TRUE without executing
|
||||
* any of the other routines.
|
||||
*/
|
||||
return (win_row(x, marker) || win_column(y, marker) ||
|
||||
win_diag_left(x, y, marker) || win_diag_right(x, y, marker));
|
||||
}
|
||||
|
||||
/*
|
||||
* Four helper functions for determining a win.
|
||||
*/
|
||||
bool
|
||||
win_column(int y, int marker)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[i][y] != marker)
|
||||
return(FALSE);
|
||||
return(TRUE);
|
||||
bool win_column(int y, int marker) {
|
||||
int i;
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[i][y] != marker)
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
bool
|
||||
win_row(int x, int marker)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[x][i] != marker)
|
||||
return(FALSE);
|
||||
return(TRUE);
|
||||
bool win_row(int x, int marker) {
|
||||
int i;
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[x][i] != marker)
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
bool
|
||||
win_diag_left(int x, int y, int marker)
|
||||
{
|
||||
int i;
|
||||
bool win_diag_left(int x, int y, int marker) {
|
||||
int i;
|
||||
|
||||
/* Check that move is on the diagonal */
|
||||
if (x != y)
|
||||
return(FALSE);
|
||||
/* Check that move is on the diagonal */
|
||||
if (x != y)
|
||||
return (FALSE);
|
||||
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[i][i] != marker)
|
||||
return(FALSE);
|
||||
return(TRUE);
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[i][i] != marker)
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
bool
|
||||
win_diag_right(int x, int y, int marker)
|
||||
{
|
||||
int i;
|
||||
bool win_diag_right(int x, int y, int marker) {
|
||||
int i;
|
||||
|
||||
/* Check that move is on the diagonal */
|
||||
if (x + y != DIM - 1)
|
||||
return(FALSE);
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[i][DIM - 1 - i] != marker)
|
||||
return(FALSE);
|
||||
return(TRUE);
|
||||
/* Check that move is on the diagonal */
|
||||
if (x + y != DIM - 1)
|
||||
return (FALSE);
|
||||
for (i = 0; i < DIM; i++)
|
||||
if (board[i][DIM - 1 - i] != marker)
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
initialize_board(void)
|
||||
{
|
||||
int i, j;
|
||||
void initialize_board(void) {
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < DIM; i++)
|
||||
for (j = 0; j < DIM; j++)
|
||||
board[i][j] = EMPTY;
|
||||
for (i = 0; i < DIM; i++)
|
||||
for (j = 0; j < DIM; j++)
|
||||
board[i][j] = EMPTY;
|
||||
}
|
||||
|
||||
int
|
||||
read_string(char *buf, int length)
|
||||
{
|
||||
int char_read;
|
||||
int i;
|
||||
int read_string(char *buf, int length) {
|
||||
int char_read;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while ((char_read = getchar()) != EOF && char_read != NEWLINE &&
|
||||
i < length) {
|
||||
buf[i] = (char) char_read;
|
||||
i++;
|
||||
putchar(char_read);
|
||||
}
|
||||
i = 0;
|
||||
while ((char_read = getchar()) != EOF && char_read != NEWLINE && i < length) {
|
||||
buf[i] = (char)char_read;
|
||||
i++;
|
||||
putchar(char_read);
|
||||
}
|
||||
|
||||
if (char_read == EOF)
|
||||
return(-1);
|
||||
if (char_read == EOF)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* If the input overflows the buffer, just cut it short
|
||||
* at length - 1 characters.
|
||||
*/
|
||||
if (i >= length)
|
||||
i--;
|
||||
buf[i] = 0;
|
||||
return(i);
|
||||
/*
|
||||
* If the input overflows the buffer, just cut it short
|
||||
* at length - 1 characters.
|
||||
*/
|
||||
if (i >= length)
|
||||
i--;
|
||||
buf[i] = 0;
|
||||
return (i);
|
||||
}
|
||||
|
||||
bool
|
||||
Strcmp(const char *a, const char *b)
|
||||
{
|
||||
if (a == NULL)
|
||||
return(b == NULL);
|
||||
if (b == NULL)
|
||||
return(FALSE);
|
||||
bool Strcmp(const char *a, const char *b) {
|
||||
if (a == NULL)
|
||||
return (b == NULL);
|
||||
if (b == NULL)
|
||||
return (FALSE);
|
||||
|
||||
while (*a && *b)
|
||||
if (*a++ != *b++)
|
||||
return(FALSE);
|
||||
|
||||
return(*a == *b);
|
||||
while (*a && *b)
|
||||
if (*a++ != *b++)
|
||||
return (FALSE);
|
||||
|
||||
return (*a == *b);
|
||||
}
|
||||
|
||||
@@ -37,9 +37,7 @@
|
||||
|
||||
#include <test/triple.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
triple("/testbin/huge");
|
||||
return 0;
|
||||
int main(void) {
|
||||
triple("/testbin/huge");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,9 +37,7 @@
|
||||
|
||||
#include <test/triple.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
triple("/testbin/matmult");
|
||||
return 0;
|
||||
int main(void) {
|
||||
triple("/testbin/matmult");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,9 +37,7 @@
|
||||
|
||||
#include <test/triple.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
triple("/testbin/sort");
|
||||
return 0;
|
||||
int main(void) {
|
||||
triple("/testbin/sort");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -45,25 +45,22 @@
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
|
||||
#define ONCELOOPS 3
|
||||
#define TWICELOOPS 2
|
||||
#define ONCELOOPS 3
|
||||
#define TWICELOOPS 2
|
||||
#define THRICELOOPS 1
|
||||
#define LOOPS (ONCELOOPS + 2*TWICELOOPS + 3*THRICELOOPS)
|
||||
#define LOOPS (ONCELOOPS + 2 * TWICELOOPS + 3 * THRICELOOPS)
|
||||
#define NUMJOBS 4
|
||||
|
||||
/*
|
||||
* Print to the console, one character at a time to encourage
|
||||
* interleaving if the semaphores aren't working.
|
||||
*/
|
||||
static
|
||||
void
|
||||
say(const char *str)
|
||||
{
|
||||
size_t i;
|
||||
static void say(const char *str) {
|
||||
size_t i;
|
||||
|
||||
for (i=0; str[i]; i++) {
|
||||
putchar(str[i]);
|
||||
}
|
||||
for (i = 0; str[i]; i++) {
|
||||
putchar(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* not used */
|
||||
@@ -85,26 +82,21 @@ sayf(const char *str, ...)
|
||||
/*
|
||||
* This should probably be in libtest.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dowait(pid_t pid, unsigned num)
|
||||
{
|
||||
pid_t r;
|
||||
int status;
|
||||
static void dowait(pid_t pid, unsigned num) {
|
||||
pid_t r;
|
||||
int status;
|
||||
|
||||
r = waitpid(pid, &status, 0);
|
||||
if (r < 0) {
|
||||
warn("waitpid");
|
||||
return;
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d (subprocess %u): Signal %d", (int)pid,
|
||||
num, WTERMSIG(status));
|
||||
}
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d (subprocess %u): Exit %d", (int)pid,
|
||||
num, WEXITSTATUS(status));
|
||||
}
|
||||
r = waitpid(pid, &status, 0);
|
||||
if (r < 0) {
|
||||
warn("waitpid");
|
||||
return;
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
warnx("pid %d (subprocess %u): Signal %d", (int)pid, num, WTERMSIG(status));
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
warnx("pid %d (subprocess %u): Exit %d", (int)pid, num,
|
||||
WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -114,276 +106,238 @@ dowait(pid_t pid, unsigned num)
|
||||
* Semaphore structure.
|
||||
*/
|
||||
struct usem {
|
||||
char name[32];
|
||||
int fd;
|
||||
char name[32];
|
||||
int fd;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
usem_init(struct usem *sem, const char *tag, unsigned num)
|
||||
{
|
||||
snprintf(sem->name, sizeof(sem->name), "sem:usemtest.%s%u", tag, num);
|
||||
sem->fd = open(sem->name, O_RDWR|O_CREAT|O_TRUNC, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(sem->fd);
|
||||
sem->fd = -1;
|
||||
static void usem_init(struct usem *sem, const char *tag, unsigned num) {
|
||||
snprintf(sem->name, sizeof(sem->name), "sem:usemtest.%s%u", tag, num);
|
||||
sem->fd = open(sem->name, O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: create", sem->name);
|
||||
}
|
||||
close(sem->fd);
|
||||
sem->fd = -1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
usem_open(struct usem *sem)
|
||||
{
|
||||
sem->fd = open(sem->name, O_RDWR);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
static void usem_open(struct usem *sem) {
|
||||
sem->fd = open(sem->name, O_RDWR);
|
||||
if (sem->fd < 0) {
|
||||
err(1, "%s: open", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
usem_close(struct usem *sem)
|
||||
{
|
||||
if (close(sem->fd) == -1) {
|
||||
warn("%s: close", sem->name);
|
||||
}
|
||||
static void usem_close(struct usem *sem) {
|
||||
if (close(sem->fd) == -1) {
|
||||
warn("%s: close", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
usem_cleanup(struct usem *sem)
|
||||
{
|
||||
(void)remove(sem->name);
|
||||
static void usem_cleanup(struct usem *sem) { (void)remove(sem->name); }
|
||||
|
||||
static void P(struct usem *sem) {
|
||||
ssize_t r;
|
||||
char c;
|
||||
|
||||
r = read(sem->fd, &c, 1);
|
||||
if (r < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "%s: read: unexpected EOF", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
P(struct usem *sem)
|
||||
{
|
||||
ssize_t r;
|
||||
char c;
|
||||
static void V(struct usem *sem) {
|
||||
ssize_t r;
|
||||
char c;
|
||||
|
||||
r = read(sem->fd, &c, 1);
|
||||
if (r < 0) {
|
||||
err(1, "%s: read", sem->name);
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "%s: read: unexpected EOF", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
V(struct usem *sem)
|
||||
{
|
||||
ssize_t r;
|
||||
char c;
|
||||
|
||||
r = write(sem->fd, &c, 1);
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "%s: write: short count", sem->name);
|
||||
}
|
||||
r = write(sem->fd, &c, 1);
|
||||
if (r < 0) {
|
||||
err(1, "%s: write", sem->name);
|
||||
}
|
||||
if (r == 0) {
|
||||
errx(1, "%s: write: short count", sem->name);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// test components
|
||||
|
||||
static
|
||||
void
|
||||
child_plain(struct usem *gosem, struct usem *waitsem, unsigned num)
|
||||
{
|
||||
static const char *const strings[NUMJOBS] = {
|
||||
"Nitwit!",
|
||||
"Blubber!",
|
||||
"Oddment!",
|
||||
"Tweak!",
|
||||
};
|
||||
static void child_plain(struct usem *gosem, struct usem *waitsem,
|
||||
unsigned num) {
|
||||
static const char *const strings[NUMJOBS] = {
|
||||
"Nitwit!",
|
||||
"Blubber!",
|
||||
"Oddment!",
|
||||
"Tweak!",
|
||||
};
|
||||
|
||||
const char *string;
|
||||
unsigned i;
|
||||
const char *string;
|
||||
unsigned i;
|
||||
|
||||
string = strings[num];
|
||||
for (i=0; i<LOOPS; i++) {
|
||||
P(gosem);
|
||||
say(string);
|
||||
V(waitsem);
|
||||
}
|
||||
string = strings[num];
|
||||
for (i = 0; i < LOOPS; i++) {
|
||||
P(gosem);
|
||||
say(string);
|
||||
V(waitsem);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
child_with_own_fd(struct usem *gosem, struct usem *waitsem, unsigned num)
|
||||
{
|
||||
usem_open(gosem);
|
||||
usem_open(waitsem);
|
||||
child_plain(gosem, waitsem, num);
|
||||
usem_close(gosem);
|
||||
usem_close(waitsem);
|
||||
static void child_with_own_fd(struct usem *gosem, struct usem *waitsem,
|
||||
unsigned num) {
|
||||
usem_open(gosem);
|
||||
usem_open(waitsem);
|
||||
child_plain(gosem, waitsem, num);
|
||||
usem_close(gosem);
|
||||
usem_close(waitsem);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
baseparent(struct usem *gosems, struct usem *waitsems)
|
||||
{
|
||||
unsigned i, j;
|
||||
static void baseparent(struct usem *gosems, struct usem *waitsems) {
|
||||
unsigned i, j;
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
usem_open(&gosems[i]);
|
||||
usem_open(&waitsems[i]);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
usem_open(&gosems[i]);
|
||||
usem_open(&waitsems[i]);
|
||||
}
|
||||
|
||||
say("Once...\n");
|
||||
for (j=0; j<ONCELOOPS; j++) {
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
say("Once...\n");
|
||||
for (j = 0; j < ONCELOOPS; j++) {
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
say("Twice...\n");
|
||||
for (j=0; j<TWICELOOPS; j++) {
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
say("Twice...\n");
|
||||
for (j = 0; j < TWICELOOPS; j++) {
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
say("Three times...\n");
|
||||
for (j=0; j<THRICELOOPS; j++) {
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
say("Three times...\n");
|
||||
for (j = 0; j < THRICELOOPS; j++) {
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
usem_close(&gosems[i]);
|
||||
usem_close(&waitsems[i]);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
usem_close(&gosems[i]);
|
||||
usem_close(&waitsems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
basetest(void)
|
||||
{
|
||||
unsigned i;
|
||||
struct usem gosems[NUMJOBS], waitsems[NUMJOBS];
|
||||
pid_t pids[NUMJOBS];
|
||||
static void basetest(void) {
|
||||
unsigned i;
|
||||
struct usem gosems[NUMJOBS], waitsems[NUMJOBS];
|
||||
pid_t pids[NUMJOBS];
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
usem_init(&gosems[i], "g", i);
|
||||
usem_init(&waitsems[i], "w", i);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
usem_init(&gosems[i], "g", i);
|
||||
usem_init(&waitsems[i], "w", i);
|
||||
}
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i] < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (pids[i] == 0) {
|
||||
child_with_own_fd(&gosems[i], &waitsems[i], i);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
baseparent(gosems, waitsems);
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i] < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (pids[i] == 0) {
|
||||
child_with_own_fd(&gosems[i], &waitsems[i], i);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
baseparent(gosems, waitsems);
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
dowait(pids[i], i);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
dowait(pids[i], i);
|
||||
}
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
usem_cleanup(&gosems[i]);
|
||||
usem_cleanup(&waitsems[i]);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
usem_cleanup(&gosems[i]);
|
||||
usem_cleanup(&waitsems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
concparent(struct usem *gosems, struct usem *waitsems)
|
||||
{
|
||||
unsigned i, j;
|
||||
static void concparent(struct usem *gosems, struct usem *waitsems) {
|
||||
unsigned i, j;
|
||||
|
||||
/*
|
||||
* Print this *before* forking as we frequently hang *in* fork.
|
||||
*say("Shoot...\n");
|
||||
*/
|
||||
for (j=0; j<LOOPS; j++) {
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
/*
|
||||
* Print this *before* forking as we frequently hang *in* fork.
|
||||
*say("Shoot...\n");
|
||||
*/
|
||||
for (j = 0; j < LOOPS; j++) {
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
V(&gosems[i]);
|
||||
P(&waitsems[i]);
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
conctest(void)
|
||||
{
|
||||
unsigned i;
|
||||
struct usem gosems[NUMJOBS], waitsems[NUMJOBS];
|
||||
pid_t pids[NUMJOBS];
|
||||
static void conctest(void) {
|
||||
unsigned i;
|
||||
struct usem gosems[NUMJOBS], waitsems[NUMJOBS];
|
||||
pid_t pids[NUMJOBS];
|
||||
|
||||
say("Shoot...\n");
|
||||
say("Shoot...\n");
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
usem_init(&gosems[i], "g", i);
|
||||
usem_init(&waitsems[i], "w", i);
|
||||
usem_open(&gosems[i]);
|
||||
usem_open(&waitsems[i]);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
usem_init(&gosems[i], "g", i);
|
||||
usem_init(&waitsems[i], "w", i);
|
||||
usem_open(&gosems[i]);
|
||||
usem_open(&waitsems[i]);
|
||||
}
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i] < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (pids[i] == 0) {
|
||||
child_plain(&gosems[i], &waitsems[i], i);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
concparent(gosems, waitsems);
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
pids[i] = fork();
|
||||
if (pids[i] < 0) {
|
||||
err(1, "fork");
|
||||
}
|
||||
if (pids[i] == 0) {
|
||||
child_plain(&gosems[i], &waitsems[i], i);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
concparent(gosems, waitsems);
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
dowait(pids[i], i);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
dowait(pids[i], i);
|
||||
}
|
||||
|
||||
for (i=0; i<NUMJOBS; i++) {
|
||||
usem_close(&gosems[i]);
|
||||
usem_close(&waitsems[i]);
|
||||
usem_cleanup(&gosems[i]);
|
||||
usem_cleanup(&waitsems[i]);
|
||||
}
|
||||
for (i = 0; i < NUMJOBS; i++) {
|
||||
usem_close(&gosems[i]);
|
||||
usem_close(&waitsems[i]);
|
||||
usem_cleanup(&gosems[i]);
|
||||
usem_cleanup(&waitsems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// concurrent use test
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
basetest();
|
||||
conctest();
|
||||
say("Passed.\n");
|
||||
return 0;
|
||||
int main(void) {
|
||||
basetest();
|
||||
conctest();
|
||||
say("Passed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user