1#!/bin/sh 2 3# 4# Copyright (c) 2012 Peter Holm <pho@FreeBSD.org> 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# Problem seen with atomic assignment of f_offset. Fixed in r238029. 30 31# Test scenario by kib@ 32 33. ../default.cfg 34 35here=`pwd` 36cd /tmp 37sed '1,/^EOF/d' < $here/$0 > f_offset.c 38mycc -o f_offset -Wall -Wextra -O2 f_offset.c -lpthread 39rm -f f_offset.c 40 41/tmp/f_offset 42 43rm -f /tmp/f_offset 44exit 0 45EOF 46/* 47 Description by kib: 48To really exercise the race conditions, all the following items must 49be fulfilled simultaneously: 501. you use 32bit host, i.e. i386 512. you operate on the file offsets larger than 4GB (but see below) 523. there are several threads or processes that operate on the same 53 file descriptor simultaneously. 54 55Please note that the normal fork(2) causes file descriptor table 56copy, so only rfork(2) call with RFFDG flag unset causes sharing. Or, 57multi-threading can be used. 58 */ 59 60#include <err.h> 61#include <fcntl.h> 62#include <pthread.h> 63#include <stdio.h> 64#include <stdlib.h> 65#include <string.h> 66#include <sys/types.h> 67#include <unistd.h> 68 69int errors, fd; 70char file[128]; 71 72#define START 0x100000000ULL 73#define N 1000000 74 75void * 76t1(void *arg __unused) 77{ 78 int i; 79 off_t offset; 80 81 offset = START + 2; 82 83 for (i = 0; i < N; i++) { 84 if (lseek(fd, offset, SEEK_SET) == -1) 85 err(1, "lseek error"); 86 } 87 88 return (0); 89} 90 91void * 92t2(void *arg __unused) 93{ 94 int i; 95 off_t offset; 96 97 offset = 1; 98 99 for (i = 0; i < N; i++) { 100 if (lseek(fd, offset, SEEK_SET) == -1) 101 err(1, "lseek error"); 102 } 103 return (0); 104} 105void * 106t3(void *arg __unused) 107{ 108 int i; 109 off_t offset; 110 111 offset = 1; 112 113 for (i = 0; i < N; i++) { 114 if ((offset = lseek(fd, 0, SEEK_CUR)) == -1) 115 err(1, "lseek error"); 116 if (offset != 1 && offset != START + 2) 117 fprintf(stderr, "FAIL #%d offset = %10jd (0x%09jx)\n", 118 errors++, offset, offset); 119 } 120 121 return (0); 122} 123 124int 125main(void) 126{ 127 pthread_t threads[3]; 128 int r; 129 int i; 130 off_t offset; 131 132 snprintf(file, sizeof(file), "file.%06d", getpid()); 133 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) 134 err(1, "%s", file); 135 136 offset = 1; 137 if (lseek(fd, offset, SEEK_SET) == -1) 138 err(1, "lseek error"); 139 140 for (i = 0; i < 20 && errors < 10; i++) { 141 if ((r = pthread_create(&threads[0], NULL, t1, 0)) != 0) 142 errc(1, r, "pthread_create()"); 143 if ((r = pthread_create(&threads[1], NULL, t2, 0)) != 0) 144 errc(1, r, "pthread_create()"); 145 if ((r = pthread_create(&threads[2], NULL, t3, 0)) != 0) 146 errc(1, r, "pthread_create()"); 147 148 if ((r = pthread_join(threads[0], NULL)) != 0) 149 errc(1, r, "pthread_join(%d)", 0); 150 if ((r = pthread_join(threads[1], NULL)) != 0) 151 errc(1, r, "pthread_join(%d)", 1); 152 if ((r = pthread_join(threads[2], NULL)) != 0) 153 errc(1, r, "pthread_join(%d)", 2); 154 } 155 close(fd); 156 if (unlink(file) == -1) 157 err(3, "unlink(%s)", file); 158 159 return (0); 160} 161