| /* |
| * 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 <stdio.h> |
| #include <stdlib.h> |
| #include <config.h> |
| |
| #ifdef HAVE_PTHREAD_H |
| #include <pthread.h> |
| #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 |
| |
| <INITIAL>[[:digit:]]+ { BEGIN(STATE_1); process_text(yytext,yyscanner); return NUMBER; } |
| <INITIAL>[[:alpha:]]+ { BEGIN(STATE_2); process_text(yytext,yyscanner); return WORD; } |
| |
| <STATE_1>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; } |
| <STATE_1>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; } |
| |
| <STATE_2>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; } |
| <STATE_2>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; } |
| |
| <INITIAL,STATE_1,STATE_2>" "|\t|\r|\n { process_text(yytext,yyscanner); } |
| <INITIAL,STATE_1,STATE_2>[^[:alnum:][:space:]\t\r\n] { |
| /*fprintf(stderr,"*** Error: bad input char '%c'.\n", yytext[0]); */ |
| yyterminate(); |
| } |
| <INITIAL,STATE_1,STATE_2>[[: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 */ |
| |