1 /*
2  * This file is part of flex.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * Neither the name of the University nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE.
22  */
23 
24 %{
25 /* A scanner file to build "scanner.c".
26    Input language is any text made of spaces, newlines, and alphanumerics.
27 
28    We create N_THREADS number of threads. Each thread has it's own scanner.
29    Each thread selects one of the files specified in ARGV, scans it, then
30    closes it. This is repeated N_SCANS numebr of times for each thread.
31 
32    The idea is to press the scanner to break under threads.
33    If we see  "Scanner Jammed", then we know
34 
35 */
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <config.h>
39 
40 #ifdef HAVE_PTHREAD_H
41 #include <pthread.h>
42 #endif
43 
44 /* A naive test for segfaults when accessing yytext. */
45 static int process_text(char* s, yyscan_t  scanner);
46 
47 %}
48 
49 %option 8bit outfile="scanner.c" prefix="test"
50 %option nounput nomain nodefault
51 %option yywrap
52 %option reentrant
53 %option warn
54 
55     /* Arbitrary states.*/
56 %x STATE_1
57 %x STATE_2
58 
59 %%
60 
61     #define NUMBER 200
62     #define WORD   201
63 
64 <INITIAL>[[:digit:]]+ { BEGIN(STATE_1); process_text(yytext,yyscanner); return NUMBER; }
65 <INITIAL>[[:alpha:]]+ { BEGIN(STATE_2); process_text(yytext,yyscanner); return WORD; }
66 
67 <STATE_1>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; }
68 <STATE_1>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; }
69 
70 <STATE_2>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; }
71 <STATE_2>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; }
72 
73 <INITIAL,STATE_1,STATE_2>" "|\t|\r|\n { process_text(yytext,yyscanner); }
74 <INITIAL,STATE_1,STATE_2>[^[:alnum:][:space:]\t\r\n] {
75         /*fprintf(stderr,"*** Error: bad input char '%c'.\n", yytext[0]); */
76         yyterminate();
77     }
78 <INITIAL,STATE_1,STATE_2>[[:space:]\r\n]+  { }
79 %%
80 
81 int yywrap( yyscan_t  scanner) { return 1; }
process_text(char * s,yyscan_t scanner)82 static int process_text(char* s, yyscan_t  scanner)
83 {
84     return (int)(*s) + (int) *(s + yyget_leng(scanner)-1);
85 }
86 
87 int main(int ARGC, char *ARGV[]);
88 
89 #ifndef HAVE_LIBPTHREAD
main(int ARGC,char * ARGV[])90   int main (int ARGC, char *ARGV[]) {
91     printf(
92        "TEST ABORTED because pthread library not available \n"
93        "-- This is expected on some systems. It is not a flex error.\n" );
94     return 0;
95   }
96 #else
97 
98 #define N_THREADS 4
99 #define N_SCANS   20
100 #define INPUT_FILE "test.input"
101 
102 /* Each thread selects the next file to scan in round-robin fashion.
103    If there are less files than threads, some threads may block. */
104 
105 static pthread_mutex_t next_lock = PTHREAD_MUTEX_INITIALIZER;
106 static pthread_mutex_t go_ahead  = PTHREAD_MUTEX_INITIALIZER;
107 static int n_files, next_file;
108 
109 static pthread_mutex_t *file_locks;
110 static char **filenames;
111 
112 
thread_func(void * arg)113 void * thread_func ( void* arg )
114 {
115     int i;
116 
117     /* Wait for go-ahead. */
118     pthread_mutex_lock( &go_ahead);
119     pthread_mutex_unlock(&go_ahead);
120 
121     for( i =0 ; i < N_SCANS ; i++ )
122     {
123         int main(int ARGC, char *ARGV[]);
124 
125         int next;
126         yyscan_t  scanner;
127         FILE * fp;
128 
129         pthread_mutex_lock ( &next_lock );
130         next = (next_file++) % n_files;
131         pthread_mutex_unlock ( &next_lock );
132 
133         pthread_mutex_lock ( &file_locks[ next ] );
134 
135         yylex_init( &scanner );
136         /*printf("Scanning file %s  #%d\n",filenames[next],i); fflush(stdout); */
137         if((fp = fopen(filenames[next],"r"))==NULL) {
138             perror("fopen");
139             return NULL;
140         }
141         yyset_in(fp,scanner);
142 
143         while( yylex( scanner) != 0)
144         {
145         }
146         fclose(fp);
147         yylex_destroy(scanner);
148         pthread_mutex_unlock ( &file_locks[ next ] );
149     }
150     return NULL;
151 }
152 
main(int ARGC,char * ARGV[])153 int main (int ARGC, char *ARGV[])
154 {
155     int i;
156     pthread_t threads[N_THREADS];
157 
158     if( ARGC < 2 ) {
159         fprintf(stderr,"*** Error: No filenames specified.\n");
160         exit(-1);
161     }
162 
163     /* Allocate and initialize the locks. One for each filename in ARGV. */
164     file_locks = (pthread_mutex_t*)malloc( (ARGC-1) * sizeof(pthread_mutex_t));
165     for( i = 0; i < ARGC-1; i++)
166         pthread_mutex_init( &file_locks[i], NULL );
167 
168     n_files = ARGC -1;
169     filenames = ARGV + 1;
170     next_file = 0;
171 
172     /* prevent threads from starting until all threads have been created. */
173     pthread_mutex_lock(&go_ahead);
174 
175     /* Create N threads then wait for them. */
176     for(i =0; i < N_THREADS ; i++ ) {
177         if( pthread_create( &threads[i], NULL, thread_func, NULL) != 0)
178         {
179             fprintf(stderr, "*** Error: pthread_create failed.\n");
180             exit(-1);
181         }
182         printf("Created thread %d.\n",i); fflush(stdout);
183     }
184 
185     /* Tell threads to begin. */
186     pthread_mutex_unlock(&go_ahead);
187 
188     for(i =0; i < N_THREADS ; i++ ) {
189         pthread_join ( threads[i], NULL );
190         printf("Thread %d done.\n", i ); fflush(stdout);
191     }
192 
193     for( i = 0; i < ARGC-1; i++)
194         pthread_mutex_destroy( &file_locks[i] );
195 
196     pthread_mutex_destroy( &next_lock );
197     pthread_mutex_destroy( &go_ahead );
198     free( file_locks );
199     printf("TEST RETURNING OK.\n");
200     return 0;
201 }
202 
203 #endif /* HAVE_LIBPTHREAD */
204 
205