Signed-Off-By: Subrata Modak<[email protected]>,
--
diff -uprN
ltp-intermediate-20090121/testcases/kernel/io/direct_io/dma_thread_diotest7.c
ltp-intermediate-20090121.modified/testcases/kernel/io/direct_io/dma_thread_diotest7.c
---
ltp-intermediate-20090121/testcases/kernel/io/direct_io/dma_thread_diotest7.c
1970-01-01 05:30:00.000000000 +0530
+++
ltp-intermediate-20090121.modified/testcases/kernel/io/direct_io/dma_thread_diotest7.c
2009-01-23 16:47:37.000000000 +0530
@@ -0,0 +1,389 @@
+/******************************************************************************/
+/* Copyright (c) Tim LaBerge <[email protected]>, 2009
*/
+/*
*/
+/* This program is free software; you can redistribute it and/or
modify */
+/* it under the terms of the GNU General Public License as published by
*/
+/* the Free Software Foundation; either version 2 of the License, or
*/
+/* (at your option) any later version.
*/
+/*
*/
+/* This program is distributed in the hope that it will be useful,
*/
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of
*/
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
*/
+/* the GNU General Public License for more details.
*/
+/*
*/
+/* You should have received a copy of the GNU General Public License
*/
+/* along with this program; if not, write to the Free Software
*/
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA */
+/*
*/
+/******************************************************************************/
+
+/******************************************************************************/
+/*
*/
+/* File: dma_thread_diotest7.c
*/
+/*
*/
+/* Description: The man page for open(2) states the following:
*/
+/* O_DIRECT (Since Linux 2.6.10). Try to minimize cache effects of
the I/O */
+/* to and from this file. In general this will degrade performance,
but it */
+/* is useful in special situations, such as when applications do
their own */
+/* caching. File I/O is done directly to/from user space buffers. The
I/O is*/
+/* synchronous, that is, at the completion of a read(2) or write(2),
data is*/
+/* guranteed to have been transferred. Under Linux 2.4 transfer
sizes, and */
+/* the alignment of user buffer and file offset must all be
multiples of */
+/* the logical block size of the file system. Under Linux 2.6
alignment to */
+/* 512-byte bound-aries suffices.
*/
+/* However, it appears that data corruption may occur when a
multithreaded */
+/* process reads into a non-page size aligned user buffer. A test
program */
+/* which reliably reproduces the problem on ext3 and xfs is attached.
The */
+/* program creates, patterns, reads, and verify a series of files. In
the */
+/* read phase, a file is opened with O_DIRECT n times, where n is the
*/
+/* number of cpu's. A single buffer large enough to contain the file
is */
+/* allocated and patterned with data not found in any of the files.
The */
+/* alignment of the buffer is controlled by a command line option.
Each file*/
+/* is read in parallel by n threads, where n is the number of cpu's.
Thread */
+/* 0 reads the first page of data from the file into the first page
of the */
+/* buffer, thread 1 reads the second page of data in to the second
page of */
+/* the buffer, and so on. Thread n - 1 reads the remainder of the
file into*/
+/* the remainder of the buffer.
*/
+/* After a thread reads data into the buffer, it immediately verifies
that */
+/* the contents of the buffer are correct. If the buffer contains
corrupt */
+/* data, the thread dumps the data surrounding the corruption and
calls */
+/* abort(). Otherwise, the thread exits.
*/
+/* Crucially, before the reader threads are dispatched, another
thread is */
+/* started which calls fork()/msleep() in a loop until all reads are
compl- */
+/* eted. The child created by fork() does nothing but call exit(0). A
comm- */
+/* and line option controls whether the buffer is aligned. In the
case wh- */
+/* ere the buffer is aligned on a page boundary, all is well. In the
case */
+/* where the buffer is aligned on a page + 512 byte offset,
corruption is */
+/* seen frequently.
*/
+/* I believe that what is happening is that in the direct IO path,
because */
+/* the user's buffer is not aligned, some user pages are being mapped
twice.*/
+/* When a fork() happens in between the calls to map the page, the
page will*/
+/* be marked as COW. When the second map happens (via
get_user_pages()), a */
+/* new physical page will be allocated and copied. Thus, there is a
race */
+/* between the completion of the first read from disk (and write to
the user*/
+/* page) and get_user_pages() mapping the page for the second time.
If the */
+/* write does not complete before the page is copied, the user will
see */
+/* stale data in the first 512 bytes of this page of their buffer.
Indeed, */
+/* this is corruption most frequently seen. (It's also possible for
the race*/
+/* to be lost the other way, so that the last 3584 bytes of the page
are */
+/* stale.)
*/
+/* The attached program (which is a heavily modified version of a
program */
+/* provided by a customer seeing this problem) reliably reproduces
the pro- */
+/* blem on any multicore linux machine on both ext3 and xfs, although
any */
+/* filesystem using the generic blockdev_direct_IO() routine is
probably */
+/* vulnerable. I've seen a few threads that mention the potential for
this */
+/* kind of problem, but no definitive solution or workaround (other
than */
+/* "Don't do that").
*/
+/* http://marc.info/?l=linux-mm&m=122668235304637&w=2
*/
+/*
*/
+/* Total Tests: 1
*/
+/*
*/
+/* Test Name: dma_thread_diotest7
*/
+/*
*/
+/* Author: Tim LaBerge <[email protected]>
*/
+/*
*/
+/* History: Reported - Jan 07 2009 - Li Zefan <[email protected]>
*/
+/* Ported - Jan 23 2009 - Subrata
<[email protected]> */
+/*
*/
+/******************************************************************************/
+
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <memory.h>
+#include <pthread.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define FILESIZE (12*1024*1024)
+#define READSIZE (1024*1024)
+
+#define FILENAME "_dma_thread_test_%.04d.tmp"
+#define FILECOUNT 100
+#define MIN_WORKERS 2
+#define MAX_WORKERS 256
+#define PAGE_SIZE getpagesize()
+
+#define true 1
+#define false 0
+
+typedef int bool;
+
+bool done = false;
+int workers = 2;
+
+#define PATTERN (0xfa)
+
+static void
+usage (void)
+{
+ fprintf(stderr, "\nUsage: dma_thread [-h | -a <alignment> [ -w
<workers>]\n"
+ "\nWith no arguments, generate test files and exit.\n"
+ "-h Display this help and exit.\n"
+ "-a align read buffer to offset <alignment>.\n"
+ "-w number of worker threads, 2 (default) to 256,\n"
+ " defaults to number of cores.\n\n"
+
+ "Run first with no arguments to generate files.\n"
+ "Then run with -a <alignment> = 512 or 0. \n");
+}
+
+typedef struct {
+ pthread_t tid;
+ int worker_number;
+ int fd;
+ int offset;
+ int length;
+ int pattern;
+ unsigned char *buffer;
+} worker_t;
+
+
+void *worker_thread(void * arg)
+{
+ int bytes_read;
+ int i,k;
+ worker_t *worker = (worker_t *) arg;
+ int offset = worker->offset;
+ int fd = worker->fd;
+ unsigned char *buffer = worker->buffer;
+ int pattern = worker->pattern;
+ int length = worker->length;
+
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ fprintf(stderr, "Failed to lseek to %d on fd %d: %s.\n",
+ offset, fd, strerror(errno));
+ exit(1);
+ }
+
+ bytes_read = read(fd, buffer, length);
+ if (bytes_read != length) {
+ fprintf(stderr, "read failed on fd %d: bytes_read %d, %s\n",
+ fd, bytes_read, strerror(errno));
+ exit(1);
+ }
+
+ /* Corruption check */
+ for (i = 0; i < length; i++) {
+ if (buffer[i] != pattern) {
+ printf("Bad data at 0x%.06x: %p, \n", i, buffer + i);
+ printf("Data dump starting at 0x%.06x:\n", i - 8);
+ printf("Expect 0x%x followed by 0x%x:\n",
+ pattern, PATTERN);
+
+ for (k = 0; k < 16; k++) {
+ printf("%02x ", buffer[i - 8 + k]);
+ if (k == 7) {
+ printf("\n");
+ }
+ }
+
+ printf("\n");
+ abort();
+ }
+ }
+
+ return 0;
+}
+
+void *fork_thread (void *arg)
+{
+ pid_t pid;
+
+ while (!done) {
+ pid = fork();
+ if (pid == 0) {
+ exit(0);
+ } else if (pid < 0) {
+ fprintf(stderr, "Failed to fork child.\n");
+ exit(1);
+ }
+ waitpid(pid, NULL, 0 );
+ usleep(100);
+ }
+
+ return NULL;
+
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned char *buffer = NULL;
+ char filename[1024];
+ int fd;
+ bool dowrite = true;
+ pthread_t fork_tid;
+ int c, n, j;
+ worker_t *worker;
+ int align = 0;
+ int offset, rc;
+
+ workers = sysconf(_SC_NPROCESSORS_ONLN);
+
+ while ((c = getopt(argc, argv, "a:hw:")) != -1) {
+ switch (c) {
+ case 'a':
+ align = atoi(optarg);
+ if (align < 0 || align > PAGE_SIZE) {
+ printf("Bad alignment %d.\n", align);
+ exit(1);
+ }
+ dowrite = false;
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+ break;
+
+ case 'w':
+ workers = atoi(optarg);
+ if (workers < MIN_WORKERS || workers > MAX_WORKERS) {
+ fprintf(stderr, "Worker count %d not between "
+ "%d and %d, inclusive.\n",
+ workers, MIN_WORKERS, MAX_WORKERS);
+ usage();
+ exit(1);
+ }
+ dowrite = false;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (argc > 1 && (optind < argc)) {
+ fprintf(stderr, "Bad command line.\n");
+ usage();
+ exit(1);
+ }
+
+ if (dowrite) {
+
+ buffer = malloc(FILESIZE);
+ if (buffer == NULL) {
+ fprintf(stderr, "Failed to malloc write buffer.\n");
+ exit(1);
+ }
+
+ for (n = 1; n <= FILECOUNT; n++) {
+ sprintf(filename, FILENAME, n);
+ fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ printf("create failed(%s): %s.\n", filename, strerror(errno));
+ exit(1);
+ }
+ memset(buffer, n, FILESIZE);
+ printf("Writing file %s.\n", filename);
+ if (write(fd, buffer, FILESIZE) != FILESIZE) {
+ printf("write failed (%s)\n", filename);
+ }
+
+ close(fd);
+ fd = -1;
+ }
+
+ free(buffer);
+ buffer = NULL;
+
+ printf("done\n");
+ exit(0);
+ }
+
+ printf("Using %d workers.\n", workers);
+
+ worker = malloc(workers * sizeof(worker_t));
+ if (worker == NULL) {
+ fprintf(stderr, "Failed to malloc worker array.\n");
+ exit(1);
+ }
+
+ for (j = 0; j < workers; j++) {
+ worker[j].worker_number = j;
+ }
+
+ printf("Using alignment %d.\n", align);
+
+ posix_memalign((void *)&buffer, PAGE_SIZE, READSIZE+ align);
+ printf("Read buffer: %p.\n", buffer);
+ for (n = 1; n <= FILECOUNT; n++) {
+
+ sprintf(filename, FILENAME, n);
+ for (j = 0; j < workers; j++) {
+ if ((worker[j].fd = open(filename, O_RDONLY|O_DIRECT)) < 0) {
+ fprintf(stderr, "Failed to open %s: %s.\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+
+ worker[j].pattern = n;
+ }
+
+ printf("Reading file %d.\n", n);
+
+ for (offset = 0; offset < FILESIZE; offset += READSIZE) {
+ memset(buffer, PATTERN, READSIZE + align);
+ for (j = 0; j < workers; j++) {
+ worker[j].offset = offset + j * PAGE_SIZE;
+ worker[j].buffer = buffer + align + j * PAGE_SIZE;
+ worker[j].length = PAGE_SIZE;
+ }
+ /* The final worker reads whatever is left over. */
+ worker[workers - 1].length = READSIZE - PAGE_SIZE * (workers - 1);
+
+ done = 0;
+
+ rc = pthread_create(&fork_tid, NULL, fork_thread, NULL);
+ if (rc != 0) {
+ fprintf(stderr, "Can't create fork thread: %s.\n",
+ strerror(rc));
+ exit(1);
+ }
+
+ for (j = 0; j < workers; j++) {
+ rc = pthread_create(&worker[j].tid,
+ NULL,
+ worker_thread,
+ worker + j);
+ if (rc != 0) {
+ fprintf(stderr, "Can't create worker thread %d: %s.\n",
+ j, strerror(rc));
+ exit(1);
+ }
+ }
+
+ for (j = 0; j < workers; j++) {
+ rc = pthread_join(worker[j].tid, NULL);
+ if (rc != 0) {
+ fprintf(stderr, "Failed to join worker thread %d: %s.\n",
+ j, strerror(rc));
+ exit(1);
+ }
+ }
+
+ /* Let the fork thread know it's ok to exit */
+ done = 1;
+
+ rc = pthread_join(fork_tid, NULL);
+ if (rc != 0) {
+ fprintf(stderr, "Failed to join fork thread: %s.\n",
+ strerror(rc));
+ exit(1);
+ }
+ }
+
+ /* Close the fd's for the next file. */
+ for (j = 0; j < workers; j++) {
+ close(worker[j].fd);
+ }
+ }
+
+ return 0;
+}
Regards--
Subrata
diff -uprN ltp-intermediate-20090121/testcases/kernel/io/direct_io/dma_thread_diotest7.c ltp-intermediate-20090121.modified/testcases/kernel/io/direct_io/dma_thread_diotest7.c
--- ltp-intermediate-20090121/testcases/kernel/io/direct_io/dma_thread_diotest7.c 1970-01-01 05:30:00.000000000 +0530
+++ ltp-intermediate-20090121.modified/testcases/kernel/io/direct_io/dma_thread_diotest7.c 2009-01-23 16:47:37.000000000 +0530
@@ -0,0 +1,389 @@
+/******************************************************************************/
+/* Copyright (c) Tim LaBerge <[email protected]>, 2009 */
+/* */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
+/* the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/******************************************************************************/
+
+/******************************************************************************/
+/* */
+/* File: dma_thread_diotest7.c */
+/* */
+/* Description: The man page for open(2) states the following: */
+/* O_DIRECT (Since Linux 2.6.10). Try to minimize cache effects of the I/O */
+/* to and from this file. In general this will degrade performance, but it */
+/* is useful in special situations, such as when applications do their own */
+/* caching. File I/O is done directly to/from user space buffers. The I/O is*/
+/* synchronous, that is, at the completion of a read(2) or write(2), data is*/
+/* guranteed to have been transferred. Under Linux 2.4 transfer sizes, and */
+/* the alignment of user buffer and file offset must all be multiples of */
+/* the logical block size of the file system. Under Linux 2.6 alignment to */
+/* 512-byte bound-aries suffices. */
+/* However, it appears that data corruption may occur when a multithreaded */
+/* process reads into a non-page size aligned user buffer. A test program */
+/* which reliably reproduces the problem on ext3 and xfs is attached. The */
+/* program creates, patterns, reads, and verify a series of files. In the */
+/* read phase, a file is opened with O_DIRECT n times, where n is the */
+/* number of cpu's. A single buffer large enough to contain the file is */
+/* allocated and patterned with data not found in any of the files. The */
+/* alignment of the buffer is controlled by a command line option. Each file*/
+/* is read in parallel by n threads, where n is the number of cpu's. Thread */
+/* 0 reads the first page of data from the file into the first page of the */
+/* buffer, thread 1 reads the second page of data in to the second page of */
+/* the buffer, and so on. Thread n - 1 reads the remainder of the file into*/
+/* the remainder of the buffer. */
+/* After a thread reads data into the buffer, it immediately verifies that */
+/* the contents of the buffer are correct. If the buffer contains corrupt */
+/* data, the thread dumps the data surrounding the corruption and calls */
+/* abort(). Otherwise, the thread exits. */
+/* Crucially, before the reader threads are dispatched, another thread is */
+/* started which calls fork()/msleep() in a loop until all reads are compl- */
+/* eted. The child created by fork() does nothing but call exit(0). A comm- */
+/* and line option controls whether the buffer is aligned. In the case wh- */
+/* ere the buffer is aligned on a page boundary, all is well. In the case */
+/* where the buffer is aligned on a page + 512 byte offset, corruption is */
+/* seen frequently. */
+/* I believe that what is happening is that in the direct IO path, because */
+/* the user's buffer is not aligned, some user pages are being mapped twice.*/
+/* When a fork() happens in between the calls to map the page, the page will*/
+/* be marked as COW. When the second map happens (via get_user_pages()), a */
+/* new physical page will be allocated and copied. Thus, there is a race */
+/* between the completion of the first read from disk (and write to the user*/
+/* page) and get_user_pages() mapping the page for the second time. If the */
+/* write does not complete before the page is copied, the user will see */
+/* stale data in the first 512 bytes of this page of their buffer. Indeed, */
+/* this is corruption most frequently seen. (It's also possible for the race*/
+/* to be lost the other way, so that the last 3584 bytes of the page are */
+/* stale.) */
+/* The attached program (which is a heavily modified version of a program */
+/* provided by a customer seeing this problem) reliably reproduces the pro- */
+/* blem on any multicore linux machine on both ext3 and xfs, although any */
+/* filesystem using the generic blockdev_direct_IO() routine is probably */
+/* vulnerable. I've seen a few threads that mention the potential for this */
+/* kind of problem, but no definitive solution or workaround (other than */
+/* "Don't do that"). */
+/* http://marc.info/?l=linux-mm&m=122668235304637&w=2 */
+/* */
+/* Total Tests: 1 */
+/* */
+/* Test Name: dma_thread_diotest7 */
+/* */
+/* Author: Tim LaBerge <[email protected]> */
+/* */
+/* History: Reported - Jan 07 2009 - Li Zefan <[email protected]> */
+/* Ported - Jan 23 2009 - Subrata <[email protected]> */
+/* */
+/******************************************************************************/
+
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <memory.h>
+#include <pthread.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define FILESIZE (12*1024*1024)
+#define READSIZE (1024*1024)
+
+#define FILENAME "_dma_thread_test_%.04d.tmp"
+#define FILECOUNT 100
+#define MIN_WORKERS 2
+#define MAX_WORKERS 256
+#define PAGE_SIZE getpagesize()
+
+#define true 1
+#define false 0
+
+typedef int bool;
+
+bool done = false;
+int workers = 2;
+
+#define PATTERN (0xfa)
+
+static void
+usage (void)
+{
+ fprintf(stderr, "\nUsage: dma_thread [-h | -a <alignment> [ -w <workers>]\n"
+ "\nWith no arguments, generate test files and exit.\n"
+ "-h Display this help and exit.\n"
+ "-a align read buffer to offset <alignment>.\n"
+ "-w number of worker threads, 2 (default) to 256,\n"
+ " defaults to number of cores.\n\n"
+
+ "Run first with no arguments to generate files.\n"
+ "Then run with -a <alignment> = 512 or 0. \n");
+}
+
+typedef struct {
+ pthread_t tid;
+ int worker_number;
+ int fd;
+ int offset;
+ int length;
+ int pattern;
+ unsigned char *buffer;
+} worker_t;
+
+
+void *worker_thread(void * arg)
+{
+ int bytes_read;
+ int i,k;
+ worker_t *worker = (worker_t *) arg;
+ int offset = worker->offset;
+ int fd = worker->fd;
+ unsigned char *buffer = worker->buffer;
+ int pattern = worker->pattern;
+ int length = worker->length;
+
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ fprintf(stderr, "Failed to lseek to %d on fd %d: %s.\n",
+ offset, fd, strerror(errno));
+ exit(1);
+ }
+
+ bytes_read = read(fd, buffer, length);
+ if (bytes_read != length) {
+ fprintf(stderr, "read failed on fd %d: bytes_read %d, %s\n",
+ fd, bytes_read, strerror(errno));
+ exit(1);
+ }
+
+ /* Corruption check */
+ for (i = 0; i < length; i++) {
+ if (buffer[i] != pattern) {
+ printf("Bad data at 0x%.06x: %p, \n", i, buffer + i);
+ printf("Data dump starting at 0x%.06x:\n", i - 8);
+ printf("Expect 0x%x followed by 0x%x:\n",
+ pattern, PATTERN);
+
+ for (k = 0; k < 16; k++) {
+ printf("%02x ", buffer[i - 8 + k]);
+ if (k == 7) {
+ printf("\n");
+ }
+ }
+
+ printf("\n");
+ abort();
+ }
+ }
+
+ return 0;
+}
+
+void *fork_thread (void *arg)
+{
+ pid_t pid;
+
+ while (!done) {
+ pid = fork();
+ if (pid == 0) {
+ exit(0);
+ } else if (pid < 0) {
+ fprintf(stderr, "Failed to fork child.\n");
+ exit(1);
+ }
+ waitpid(pid, NULL, 0 );
+ usleep(100);
+ }
+
+ return NULL;
+
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned char *buffer = NULL;
+ char filename[1024];
+ int fd;
+ bool dowrite = true;
+ pthread_t fork_tid;
+ int c, n, j;
+ worker_t *worker;
+ int align = 0;
+ int offset, rc;
+
+ workers = sysconf(_SC_NPROCESSORS_ONLN);
+
+ while ((c = getopt(argc, argv, "a:hw:")) != -1) {
+ switch (c) {
+ case 'a':
+ align = atoi(optarg);
+ if (align < 0 || align > PAGE_SIZE) {
+ printf("Bad alignment %d.\n", align);
+ exit(1);
+ }
+ dowrite = false;
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+ break;
+
+ case 'w':
+ workers = atoi(optarg);
+ if (workers < MIN_WORKERS || workers > MAX_WORKERS) {
+ fprintf(stderr, "Worker count %d not between "
+ "%d and %d, inclusive.\n",
+ workers, MIN_WORKERS, MAX_WORKERS);
+ usage();
+ exit(1);
+ }
+ dowrite = false;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (argc > 1 && (optind < argc)) {
+ fprintf(stderr, "Bad command line.\n");
+ usage();
+ exit(1);
+ }
+
+ if (dowrite) {
+
+ buffer = malloc(FILESIZE);
+ if (buffer == NULL) {
+ fprintf(stderr, "Failed to malloc write buffer.\n");
+ exit(1);
+ }
+
+ for (n = 1; n <= FILECOUNT; n++) {
+ sprintf(filename, FILENAME, n);
+ fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ printf("create failed(%s): %s.\n", filename, strerror(errno));
+ exit(1);
+ }
+ memset(buffer, n, FILESIZE);
+ printf("Writing file %s.\n", filename);
+ if (write(fd, buffer, FILESIZE) != FILESIZE) {
+ printf("write failed (%s)\n", filename);
+ }
+
+ close(fd);
+ fd = -1;
+ }
+
+ free(buffer);
+ buffer = NULL;
+
+ printf("done\n");
+ exit(0);
+ }
+
+ printf("Using %d workers.\n", workers);
+
+ worker = malloc(workers * sizeof(worker_t));
+ if (worker == NULL) {
+ fprintf(stderr, "Failed to malloc worker array.\n");
+ exit(1);
+ }
+
+ for (j = 0; j < workers; j++) {
+ worker[j].worker_number = j;
+ }
+
+ printf("Using alignment %d.\n", align);
+
+ posix_memalign((void *)&buffer, PAGE_SIZE, READSIZE+ align);
+ printf("Read buffer: %p.\n", buffer);
+ for (n = 1; n <= FILECOUNT; n++) {
+
+ sprintf(filename, FILENAME, n);
+ for (j = 0; j < workers; j++) {
+ if ((worker[j].fd = open(filename, O_RDONLY|O_DIRECT)) < 0) {
+ fprintf(stderr, "Failed to open %s: %s.\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+
+ worker[j].pattern = n;
+ }
+
+ printf("Reading file %d.\n", n);
+
+ for (offset = 0; offset < FILESIZE; offset += READSIZE) {
+ memset(buffer, PATTERN, READSIZE + align);
+ for (j = 0; j < workers; j++) {
+ worker[j].offset = offset + j * PAGE_SIZE;
+ worker[j].buffer = buffer + align + j * PAGE_SIZE;
+ worker[j].length = PAGE_SIZE;
+ }
+ /* The final worker reads whatever is left over. */
+ worker[workers - 1].length = READSIZE - PAGE_SIZE * (workers - 1);
+
+ done = 0;
+
+ rc = pthread_create(&fork_tid, NULL, fork_thread, NULL);
+ if (rc != 0) {
+ fprintf(stderr, "Can't create fork thread: %s.\n",
+ strerror(rc));
+ exit(1);
+ }
+
+ for (j = 0; j < workers; j++) {
+ rc = pthread_create(&worker[j].tid,
+ NULL,
+ worker_thread,
+ worker + j);
+ if (rc != 0) {
+ fprintf(stderr, "Can't create worker thread %d: %s.\n",
+ j, strerror(rc));
+ exit(1);
+ }
+ }
+
+ for (j = 0; j < workers; j++) {
+ rc = pthread_join(worker[j].tid, NULL);
+ if (rc != 0) {
+ fprintf(stderr, "Failed to join worker thread %d: %s.\n",
+ j, strerror(rc));
+ exit(1);
+ }
+ }
+
+ /* Let the fork thread know it's ok to exit */
+ done = 1;
+
+ rc = pthread_join(fork_tid, NULL);
+ if (rc != 0) {
+ fprintf(stderr, "Failed to join fork thread: %s.\n",
+ strerror(rc));
+ exit(1);
+ }
+ }
+
+ /* Close the fd's for the next file. */
+ for (j = 0; j < workers; j++) {
+ close(worker[j].fd);
+ }
+ }
+
+ return 0;
+}
------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list