/* * This file is part of flex. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. */ %{ /* A scanner file to build "scanner.c". Input language is any text made of spaces, newlines, and alphanumerics. We create N_THREADS number of threads. Each thread has it's own scanner. Each thread selects one of the files specified in ARGV, scans it, then closes it. This is repeated N_SCANS number of times for each thread. The idea is to press the scanner to break under threads. If we see "Scanner Jammed", then we know */ #include #include #include #ifdef HAVE_PTHREAD_H #include #endif /* A naive test for segfaults when accessing yytext. */ static int process_text(char* s, yyscan_t scanner); %} %option 8bit prefix="test" %option nounput nomain nodefault noinput %option yywrap %option reentrant %option warn /* Arbitrary states.*/ %x STATE_1 %x STATE_2 %% #define NUMBER 200 #define WORD 201 [[:digit:]]+ { BEGIN(STATE_1); process_text(yytext,yyscanner); return NUMBER; } [[:alpha:]]+ { BEGIN(STATE_2); process_text(yytext,yyscanner); return WORD; } [[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; } [[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; } [[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; } [[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; } " "|\t|\r|\n { process_text(yytext,yyscanner); } [^[:alnum:][:space:]\t\r\n] { /*fprintf(stderr,"*** Error: bad input char '%c'.\n", yytext[0]); */ yyterminate(); } [[:space:]\r\n]+ { } %% int testwrap( yyscan_t scanner) { (void)scanner; return 1; } static int process_text(char* s, yyscan_t scanner) { (void)scanner; return (int)(*s) + (int) *(s + testget_leng(scanner)-1); } int main(int ARGC, char *ARGV[]); #ifndef HAVE_PTHREAD_H int main (int ARGC, char *ARGV[]) { puts( "TEST ABORTED because pthread library not available \n" "-- This is expected on some systems. It is not a flex error."); /* Exit status for a skipped test */ return 77; } #else #define N_THREADS 4 #define N_SCANS 20 /* Each thread selects the next file to scan in round-robin fashion. If there are less files than threads, some threads may block. */ static pthread_mutex_t next_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t go_ahead = PTHREAD_MUTEX_INITIALIZER; static int n_files, next_file; static pthread_mutex_t *file_locks; static char **filenames; static void * thread_func ( void* arg ) { int i; (void)arg; /* Wait for go-ahead. */ pthread_mutex_lock( &go_ahead); pthread_mutex_unlock(&go_ahead); for( i =0 ; i < N_SCANS ; i++ ) { int next; yyscan_t scanner; FILE * fp; pthread_mutex_lock ( &next_lock ); next = (next_file++) % n_files; pthread_mutex_unlock ( &next_lock ); pthread_mutex_lock ( &file_locks[ next ] ); testlex_init( &scanner ); /*printf("Scanning file %s #%d\n",filenames[next],i); fflush(stdout); */ if((fp = fopen(filenames[next],"r"))==NULL) { perror("fopen"); return NULL; } testset_in(fp,scanner); while( testlex( scanner) != 0) { } fclose(fp); testlex_destroy(scanner); pthread_mutex_unlock ( &file_locks[ next ] ); } return NULL; } int main (int ARGC, char *ARGV[]) { int i; pthread_t threads[N_THREADS]; if( ARGC < 2 ) { fprintf(stderr,"*** Error: No filenames specified.\n"); exit(-1); } /* Allocate and initialize the locks. One for each filename in ARGV. */ file_locks = malloc((size_t) (ARGC-1) * sizeof(pthread_mutex_t)); for( i = 0; i < ARGC-1; i++) pthread_mutex_init( &file_locks[i], NULL ); n_files = ARGC -1; filenames = ARGV + 1; next_file = 0; /* prevent threads from starting until all threads have been created. */ pthread_mutex_lock(&go_ahead); /* Create N threads then wait for them. */ for(i =0; i < N_THREADS ; i++ ) { if( pthread_create( &threads[i], NULL, thread_func, NULL) != 0) { fprintf(stderr, "*** Error: pthread_create failed.\n"); exit(-1); } printf("Created thread %d.\n",i); fflush(stdout); } /* Tell threads to begin. */ pthread_mutex_unlock(&go_ahead); for(i =0; i < N_THREADS ; i++ ) { pthread_join ( threads[i], NULL ); printf("Thread %d done.\n", i ); fflush(stdout); } for( i = 0; i < ARGC-1; i++) pthread_mutex_destroy( &file_locks[i] ); pthread_mutex_destroy( &next_lock ); pthread_mutex_destroy( &go_ahead ); free( file_locks ); printf("TEST RETURNING OK.\n"); return 0; } #endif /* HAVE_PTHREAD_H */