15 return clock_gettime(CLOCK_MONOTONIC, &now) ? -1 : (int64_t)now.tv_sec * 1000000000 + now.tv_nsec;
17void vm_pause(
int milliseconds) {
18 struct timespec pause = {milliseconds / 1000, (milliseconds % 1000) * 1000000};
19 while (nanosleep(&pause, &pause) && errno == EINTR) {
22int vm_wait(
volatile int* flag,
int milliseconds) {
23 int64_t deadline = vm_now() + (int64_t)milliseconds * 1000000;
24 while (!__atomic_load_n(flag, __ATOMIC_ACQUIRE)) {
25 if (vm_now() >= deadline)
31int vm_reap(pid_t child,
int milliseconds) {
32 int64_t deadline = vm_now() + (int64_t)milliseconds * 1000000;
33 while (vm_now() < deadline) {
35 pid_t result = waitpid(child, &status, WNOHANG);
37 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
38 if (result < 0 && errno != EINTR)
43 while (waitpid(child, NULL, 0) < 0 && errno == EINTR) {
47static void expected_fault(
int signal) {
51int vm_fault(
void* address,
int writing,
int expected_signal) {
57 struct sigaction action = {.sa_handler = expected_fault};
58 sigemptyset(&action.sa_mask);
59 if (sigaction(expected_signal, &action, NULL))
62 *(
volatile unsigned char*)address = 0x7e;
64 volatile unsigned char value = *(
volatile unsigned char*)address;
69 return vm_reap(child, 4000);
71int vm_file(
size_t pages,
int* readonly) {
72 static unsigned sequence;
74 snprintf(name,
sizeof(name),
"/tmp/vm-contract-%ld-%u", (
long)getpid(), sequence++);
75 int fd = open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
78 unsigned char* bytes = malloc(vm_page);
79 int error = bytes == NULL;
82 for (
size_t n = 0; !error && n < pages; ++n) {
83 memset(bytes, 0x20 + n, vm_page);
84 error = write(fd, bytes, vm_page) != (ssize_t)vm_page;
87 if (!error && readonly) {
88 *readonly = open(name, O_RDONLY);
89 error = *readonly < 0;
94 if (readonly && *readonly >= 0) {
103int vm_uniform(
const unsigned char* bytes,
size_t length,
unsigned char value) {
104 for (
size_t n = 0; n < length; ++n)
105 if (bytes[n] != value)
110static int run(
const char* name,
int (*test)(
void)) {
111 printf(
"VM-EXPANSION-CONTRACT: BEGIN %s\n", name);
113 pid_t child = fork();
121 _exit(result ? 1 : 0);
123 int result = vm_reap(child, 45000);
124 printf(
"VM-EXPANSION-CONTRACT: %s %s status=%d\n", result ?
"FAIL" :
"PASS", name, result);
128int main(
int argc,
char** argv) {
129 vm_page = (size_t)sysconf(_SC_PAGESIZE);
130 if (!vm_page || vm_page > 65536 || (vm_page & (vm_page - 1)))
132 static const struct {
136 {
"remap", vm_test_remap}, {
"residency", vm_test_residency}, {
"discard", vm_test_discard}};
138 for (
unsigned n = 0; n <
sizeof(suites) /
sizeof(suites[0]); ++n) {
139 if (argc > 1 && strcmp(argv[1], suites[n].name))
142 if (run(suites[n].name, suites[n].test))
147 puts(
"VM-EXPANSION-CONTRACT: END PASS");