1#!/bin/sh 2 3# 4# Copyright (c) 2025 Peter Holm <pho@FreeBSD.org> 5# 6# SPDX-License-Identifier: BSD-2-Clause 7# 8 9. ../default.cfg 10set -u 11prog=$(basename "$0" .sh) 12cat > /tmp/$prog.c <<EOF 13#include <sys/types.h> 14#include <sys/mman.h> 15 16#include <assert.h> 17#include <err.h> 18#include <pthread.h> 19#include <signal.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <time.h> 24#include <unistd.h> 25 26static pthread_mutex_t write_mutex; 27static volatile int done; 28static int go, n, *once, *p, ps; 29 30static void * 31wr(void *arg) 32{ 33 int idx; 34 35 alarm(180); 36 idx = *(int *)arg; 37 while (go == 0) 38 usleep(100); 39 while (go == 1) { 40 while (go == 1 && once[idx] == 0) 41 usleep(100); 42 if (go == 0) 43 break; 44 p[idx]++; 45 once[idx] = 0; 46 pthread_mutex_lock(&write_mutex); 47 done++; 48 pthread_mutex_unlock(&write_mutex); 49 } 50 return(NULL); 51} 52 53static void 54setonce(int val) 55{ 56 int i; 57 58 for (i = 0; i < n; i++) 59 once[i] = val; 60} 61 62static void 63usage(char *prog) { 64 fprintf(stderr, "Usage: %s <number of threads>\n", prog); 65 _exit(1); 66} 67 68int 69main(int argc, char *argv[]) 70{ 71 pthread_t *tid; 72 time_t start; 73 int *arg; 74 int e, i, nb, r; 75 76 if (argc != 2) 77 usage(argv[0]); 78 if (sscanf(argv[1], "%d", &n) != 1) 79 usage(argv[0]); 80 if (n > 1) 81 n--; 82 if ((tid = calloc(n, sizeof(pthread_t *))) == NULL) 83 err(1, "calloc()"); 84 if ((once = calloc(n, sizeof(int *))) == NULL) 85 err(1, "calloc()"); 86 setonce(0); 87 88 ps = getpagesize(); 89 p = mmap(NULL, n * ps, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0); 90 go = 0; 91 pthread_mutex_init(&write_mutex, NULL); 92 for (i = 0; i < n; i++) { 93 arg = malloc(sizeof(int)); 94 *arg = i; 95 if ((e = pthread_create(&tid[i], NULL, wr, (void *)arg)) != 0) 96 errc(1, e, "pthread_create()"); 97 } 98 go = 1; 99 100 nb = 0; 101 start = time(NULL); 102 while (time(NULL) - start < 120) { 103 if (mprotect(p, n * ps, PROT_READ|PROT_WRITE) == -1) 104 err(1, "mprotect(PROT_READ)"); 105 done = 0; 106 setonce(1); 107 while (done != n) 108 usleep(100); 109 if (mprotect(p, n * ps, PROT_READ) == -1) 110 err(1, "mprotect(PROT_READ)"); 111 nb++; 112 usleep(100); 113 } 114 go = 0; 115 for (i = 0; i < n; i++) { 116 if ((e = pthread_join(tid[i], NULL)) != 0) 117 errc(1, e, "pthread_join() in loop %d", i); 118 } 119 r = 0; 120 for (i = 1; i < n; i++) { 121 if (p[0] != p[i]) 122 r++; 123 } 124 if (r != 0) { 125 fprintf(stderr, "%d loops.\n", nb); 126 for (i = 0; i < n; i++) 127 fprintf(stderr, "p[%3d] = %d\n", i, p[i]); 128 } 129 130 return (r); 131} 132EOF 133mycc -o /tmp/$prog -Wall -Wextra -O0 -g /tmp/$prog.c -lpthread || exit 1 134 135n=`sysctl -n hw.ncpu` 136if [ $# -eq 1 ]; then 137 echo $1 | grep -Eq '^[0-9]+$' && n=$1 138fi 139../testcases/swap/swap -t 2m > /dev/null & 140sleep 10 141/tmp/$prog $n; s=$? 142pkill -9 swap 143wait 144 145rm -d /tmp/$prog /tmp/$prog.c 146exit $s 147