| /* |
| * |
| * Copyright (c) International Business Machines Corp., 2001 |
| * |
| * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| /* |
| * FILE : openfile.c |
| * DESCRIPTION : Create files and open simultaneously |
| * HISTORY: |
| * 03/21/2001 Paul Larson (plars@us.ibm.com) |
| * -Ported |
| * 11/01/2001 Mnaoj Iyer (manjo@austin.ibm.com) |
| * - Modified. |
| * added #inclide <unistd.h> |
| * |
| */ |
| |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include <unistd.h> |
| |
| #include "test.h" |
| |
| char *TCID = "openfile01"; /* Test program identifier. */ |
| int TST_TOTAL = 1; |
| |
| #define MAXFILES 32768 |
| #define MAXTHREADS 10 |
| |
| /* Control Structure */ |
| struct cb { |
| pthread_mutex_t m; |
| pthread_cond_t init_cv; |
| pthread_cond_t thr_cv; |
| int thr_sleeping; |
| } c; |
| |
| /* Global Variables */ |
| int numthreads = 10, numfiles = 10; |
| int debug = 0; |
| char *filename = "FILETOOPEN"; |
| |
| void setup(void) |
| { |
| tst_tmpdir(); |
| } |
| |
| void cleanup(void) |
| { |
| tst_rmdir(); |
| |
| } |
| |
| /* Procedures */ |
| void *threads(void *thread_id); |
| |
| /* ************************************************************************** |
| * MAIN PROCEDURE * |
| ************************************************************************** */ |
| |
| int main(int argc, char *argv[]) |
| { |
| int i, opt, badopts = 0; |
| FILE *fd; |
| pthread_t th_id; |
| char msg[80] = ""; |
| extern char *optarg; |
| |
| while ((opt = getopt(argc, argv, "df:t:h")) != EOF) { |
| switch ((char)opt) { |
| case 'd': |
| debug = 1; |
| break; |
| case 'f': |
| numfiles = atoi(optarg); |
| if (numfiles <= 0) |
| badopts = 1; |
| break; |
| case 't': |
| numthreads = atoi(optarg); |
| if (numthreads <= 0) |
| badopts = 1; |
| break; |
| case 'h': |
| default: |
| printf("Usage: openfile [-d] -f FILES -t THREADS\n"); |
| _exit(1); |
| } |
| } |
| if (badopts) { |
| printf("Usage: openfile [-d] -f FILES -t THREADS\n"); |
| _exit(1); |
| } |
| |
| setup(); |
| |
| /* Check if numthreads is less than MAXFILES */ |
| if (numfiles > MAXFILES) { |
| sprintf(msg, "%s\nCannot use %d files", msg, numfiles); |
| sprintf(msg, "%s, used %d files instead\n", msg, MAXFILES); |
| numfiles = MAXFILES; |
| } |
| |
| /* Check if numthreads is less than MAXTHREADS */ |
| if (numthreads > MAXTHREADS) { |
| sprintf(msg, "%s\nCannot use %d threads", msg, numthreads); |
| sprintf(msg, "%s, used %d threads instead\n", msg, MAXTHREADS); |
| numthreads = MAXTHREADS; |
| } |
| |
| /* Create files */ |
| if ((fd = fopen(filename, "w")) == NULL) { |
| tst_resm(TFAIL, "Could not create file"); |
| cleanup(); |
| } |
| |
| /* Initialize thread control variables, lock & condition */ |
| pthread_mutex_init(&c.m, NULL); |
| pthread_cond_init(&c.init_cv, NULL); |
| pthread_cond_init(&c.thr_cv, NULL); |
| c.thr_sleeping = 0; |
| |
| /* Grab mutex lock */ |
| if (pthread_mutex_lock(&c.m)) { |
| tst_resm(TFAIL, "failed to grab mutex lock"); |
| fclose(fd); |
| unlink(filename); |
| cleanup(); |
| } |
| |
| printf("Creating Reading Threads\n"); |
| |
| /* Create threads */ |
| for (i = 0; i < numthreads; i++) |
| if (pthread_create(&th_id, NULL, threads, |
| (void *)(uintptr_t) i)) { |
| tst_resm(TFAIL, |
| "failed creating a pthread; increase limits"); |
| fclose(fd); |
| unlink(filename); |
| cleanup(); |
| } |
| |
| /* Sleep until all threads are created */ |
| while (c.thr_sleeping != numthreads) |
| if (pthread_cond_wait(&c.init_cv, &c.m)) { |
| tst_resm(TFAIL, |
| "error while waiting for reading threads"); |
| fclose(fd); |
| unlink(filename); |
| cleanup(); |
| } |
| |
| /* Wake up all threads */ |
| if (pthread_cond_broadcast(&c.thr_cv)) { |
| tst_resm(TFAIL, "failed trying to wake up reading threads"); |
| fclose(fd); |
| unlink(filename); |
| cleanup(); |
| } |
| /* Release mutex lock */ |
| if (pthread_mutex_unlock(&c.m)) { |
| tst_resm(TFAIL, "failed to release mutex lock"); |
| fclose(fd); |
| unlink(filename); |
| cleanup(); |
| } |
| |
| tst_resm(TPASS, "Threads are done reading"); |
| |
| fclose(fd); |
| unlink(filename); |
| cleanup(); |
| _exit(0); |
| } |
| |
| /* ************************************************************************** |
| * OTHER PROCEDURES * |
| ************************************************************************** */ |
| |
| void close_files(FILE * fd_list[], int len) |
| { |
| int i; |
| for (i = 0; i < len; i++) { |
| fclose(fd_list[i]); |
| } |
| } |
| |
| /* threads: Each thread opens the files specified */ |
| void *threads(void *thread_id_) |
| { |
| int thread_id = (uintptr_t) thread_id_; |
| char errmsg[80]; |
| FILE *fd_list[MAXFILES]; |
| int i; |
| |
| /* Open files */ |
| for (i = 0; i < numfiles; i++) { |
| if (debug) |
| printf("Thread %d : Opening file number %d \n", |
| thread_id, i); |
| if ((fd_list[i] = fopen(filename, "rw")) == NULL) { |
| sprintf(errmsg, "FAIL - Couldn't open file #%d", i); |
| perror(errmsg); |
| if (i > 0) { |
| close_files(fd_list, i - 1); |
| } |
| unlink(filename); |
| pthread_exit((void *)1); |
| } |
| } |
| |
| /* Grab mutex lock */ |
| if (pthread_mutex_lock(&c.m)) { |
| perror("FAIL - failed to grab mutex lock"); |
| close_files(fd_list, numfiles); |
| unlink(filename); |
| pthread_exit((void *)1); |
| } |
| |
| /* Check if you should wake up main thread */ |
| if (++c.thr_sleeping == numthreads) |
| if (pthread_cond_signal(&c.init_cv)) { |
| perror("FAIL - failed to signal main thread"); |
| close_files(fd_list, numfiles); |
| unlink(filename); |
| pthread_exit((void *)1); |
| } |
| |
| /* Sleep until woken up */ |
| if (pthread_cond_wait(&c.thr_cv, &c.m)) { |
| perror("FAIL - failed to wake up correctly"); |
| close_files(fd_list, numfiles); |
| unlink(filename); |
| pthread_exit((void *)1); |
| } |
| |
| /* Release mutex lock */ |
| if (pthread_mutex_unlock(&c.m)) { |
| perror("FAIL - failed to release mutex lock"); |
| close_files(fd_list, numfiles); |
| unlink(filename); |
| pthread_exit((void *)1); |
| } |
| |
| /* Close file handles and exit */ |
| close_files(fd_list, numfiles); |
| unlink(filename); |
| pthread_exit(NULL); |
| } |