/* ETXTBSY race example from https://github.com/golang/go/issues/22315 */ #include #include #include #include #include #include #include #include #include #include static void *runner(void *); int main(void) { pthread_t thr[20]; for (int i=1; i<20; i++) pthread_create(&thr[i], 0, runner, (void*)(uintptr_t)i); runner(0); } static const char *script = "#!/bin/sh\nexit 0\n"; static void * runner(void *v) { int i, fd, pid, status; char buf[100], *argv[2]; i = (int)(uintptr_t)v; snprintf(buf, sizeof buf, "txtbusy-%d", i); argv[0] = buf; argv[1] = 0; for(;;) { fd = open(buf, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0777); if(fd < 0) { perror("open"); exit(2); } write(fd, script, strlen(script)); #ifndef NOWAIT flock(fd, LOCK_EX); close(fd); fd = open(buf, O_RDONLY|O_CLOEXEC); flock(fd, LOCK_SH); #endif close(fd); pid = fork(); if(pid < 0) { perror("fork"); exit(2); } if(pid == 0) { execve(buf, argv, 0); exit(errno); } if(waitpid(pid, &status, 0) < 0) { perror("waitpid"); exit(2); } if(!WIFEXITED(status)) { perror("waitpid not exited"); exit(2); } status = WEXITSTATUS(status); if(status != 0) fprintf(stderr, "exec: %d %s\n", status, strerror(status)); } return 0; }