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