version 1.4w10UCIb17
[polyglot.git] / engine.cpp
1 #ifndef _WIN32\r
2 \r
3 // engine.cpp\r
4 \r
5 // includes\r
6 \r
7 #include <cerrno>\r
8 #include <cstdarg>\r
9 #include <cstdio>\r
10 #include <cstdlib>\r
11 #include <cstring>\r
12 \r
13 #include <sys/types.h>\r
14 #include <sys/resource.h>\r
15 #include <unistd.h>\r
16 \r
17 #include "engine.h"\r
18 #include "io.h"\r
19 #include "option.h"\r
20 #include "util.h"\r
21 \r
22 \r
23 // constants\r
24 \r
25 static const int StringSize = 4096;\r
26 \r
27 // variables\r
28 \r
29 engine_t Engine[1];\r
30 \r
31 // prototypes\r
32 \r
33 static void my_close (int fd);\r
34 static void my_dup2  (int old_fd, int new_fd);\r
35 \r
36 // functions\r
37 \r
38 // engine_is_ok()\r
39 \r
40 bool engine_is_ok(const engine_t * engine) {\r
41 \r
42    if (engine == NULL) return false;\r
43 \r
44    if (!io_is_ok(engine->io)) return false;\r
45 \r
46    return true;\r
47 }\r
48 \r
49 // engine_open()\r
50 \r
51 void engine_open(engine_t * engine) {\r
52 \r
53    const char * dir, * command;\r
54    char string[StringSize];\r
55    int argc;\r
56    char * ptr;\r
57    char * argv[256];\r
58    int from_engine[2], to_engine[2];\r
59    pid_t pid;\r
60 \r
61    ASSERT(engine!=NULL);\r
62 \r
63    // init\r
64 \r
65    dir = option_get_string("EngineDir");\r
66    my_log("POLYGLOT Dir \"%s\"\n",dir);\r
67 \r
68    command = option_get_string("EngineCommand");\r
69    my_log("POLYGLOT Command \"%s\"\n",command);\r
70 \r
71    // parse the command line and create the argument list\r
72 \r
73    if (strlen(command) >= StringSize) my_fatal("engine_open(): buffer overflow\n");\r
74    strcpy(string,command);\r
75 \r
76    argc = 0;\r
77 \r
78    for (ptr = strtok(string," "); ptr != NULL; ptr = strtok(NULL," ")) {\r
79       argv[argc++] = ptr;\r
80    }\r
81 \r
82    argv[argc] = NULL;\r
83 \r
84    // create the pipes\r
85 \r
86    if (pipe(from_engine) == -1) {\r
87       my_fatal("engine_open(): pipe(): %s\n",strerror(errno));\r
88    }\r
89 \r
90    if (pipe(to_engine) == -1) {\r
91       my_fatal("engine_open(): pipe(): %s\n",strerror(errno));\r
92    }\r
93 \r
94    // create the child process\r
95 \r
96    pid = fork();\r
97 \r
98    if (pid == -1) {\r
99 \r
100       my_fatal("engine_open(): fork(): %s\n",strerror(errno));\r
101 \r
102    } else if (pid == 0) {\r
103 \r
104       // child = engine\r
105 \r
106       // close unused pipe descriptors to avoid deadlocks\r
107 \r
108       my_close(from_engine[0]);\r
109       my_close(to_engine[1]);\r
110 \r
111       // attach the pipe to standard input\r
112 \r
113       my_dup2(to_engine[0],STDIN_FILENO);\r
114       my_close(to_engine[0]);\r
115 \r
116       // attach the pipe to standard output\r
117 \r
118       my_dup2(from_engine[1],STDOUT_FILENO);\r
119       my_close(from_engine[1]);\r
120 \r
121       // attach standard error to standard output\r
122 \r
123       my_dup2(STDOUT_FILENO,STDERR_FILENO);\r
124 \r
125       // set a low priority\r
126 \r
127       if (option_get_bool("UseNice")) {\r
128           my_log("POLYGLOT Adjust Engine Piority");\r
129           nice(option_get_int("NiceValue"));\r
130       }\r
131 \r
132       // change the current directory\r
133 \r
134       if (dir[0] != '\0' && chdir(dir) == -1) {\r
135          my_fatal("engine_open(): chdir(): %s\n",strerror(errno));\r
136       }\r
137 \r
138       // launch the new executable file\r
139 \r
140       execvp(argv[0],&argv[0]);\r
141 \r
142       // execvp() only returns when an error has occured\r
143 \r
144       my_fatal("engine_open(): execvp(): %s\n",strerror(errno));\r
145 \r
146    } else { // pid > 0\r
147 \r
148       ASSERT(pid>0);\r
149 \r
150       // parent = PolyGlot\r
151 \r
152       // close unused pipe descriptors to avoid deadlocks\r
153 \r
154       my_close(from_engine[1]);\r
155       my_close(to_engine[0]);\r
156 \r
157       // fill in the engine struct\r
158 \r
159       engine->io->in_fd = from_engine[0];\r
160       engine->io->out_fd = to_engine[1];\r
161       engine->io->name = "Engine";\r
162       engine->pid=pid;\r
163       engine->state|=ENGINE_ACTIVE; // can we test if this really true?\r
164 \r
165       io_init(engine->io);\r
166    }\r
167 }\r
168 \r
169 // engine_active\r
170 \r
171 bool engine_active(engine_t *engine){\r
172     return (engine->state & ENGINE_ACTIVE)!=0;\r
173 }\r
174 \r
175 // engine_eof\r
176 \r
177 bool engine_eof(engine_t *engine){\r
178     return (engine->state & ENGINE_EOF)!=0;\r
179 }\r
180 \r
181 // engine_set_nice_value()\r
182 \r
183 void engine_set_nice_value(engine_t * engine, int value){\r
184     setpriority(PRIO_PROCESS,engine->pid,value);\r
185 }\r
186 \r
187 \r
188 // engine_close()\r
189 \r
190 void engine_close(engine_t * engine) {\r
191 \r
192    ASSERT(engine_is_ok(engine));\r
193 \r
194    char string[StringSize];\r
195    io_close(engine->io);\r
196        // TODO: timeout\r
197    while (!engine_eof(engine)) {\r
198        engine_get(engine,string,StringSize); \r
199    }\r
200 \r
201 }\r
202 \r
203 // engine_get()\r
204 \r
205 void engine_get(engine_t * engine, char string[], int size) {\r
206 \r
207    ASSERT(engine_is_ok(engine));\r
208    ASSERT(string!=NULL);\r
209    ASSERT(size>=256);\r
210 \r
211    while (!io_line_ready(engine->io)) {\r
212       io_get_update(engine->io);\r
213    }\r
214 \r
215    if (!io_get_line(engine->io,string,size)) { // EOF\r
216        engine->state|=ENGINE_EOF;\r
217    }\r
218 }\r
219 \r
220 // engine_send()\r
221 \r
222 void engine_send(engine_t * engine, const char format[], ...) {\r
223 \r
224    va_list arg_list;\r
225    char string[StringSize];\r
226 \r
227    ASSERT(engine_is_ok(engine));\r
228    ASSERT(format!=NULL);\r
229 \r
230    // format\r
231 \r
232    va_start(arg_list,format);\r
233    vsprintf(string,format,arg_list);\r
234    va_end(arg_list);\r
235 \r
236    // send\r
237 \r
238    io_send(engine->io,"%s",string);\r
239 }\r
240 \r
241 // engine_send_queue()\r
242 \r
243 void engine_send_queue(engine_t * engine, const char format[], ...) {\r
244 \r
245    va_list arg_list;\r
246    char string[StringSize];\r
247 \r
248    ASSERT(engine_is_ok(engine));\r
249    ASSERT(format!=NULL);\r
250 \r
251    // format\r
252 \r
253    va_start(arg_list,format);\r
254    vsprintf(string,format,arg_list);\r
255    va_end(arg_list);\r
256 \r
257    // send\r
258 \r
259    io_send_queue(engine->io,"%s",string);\r
260 }\r
261 \r
262 // my_close()\r
263 \r
264 static void my_close(int fd) {\r
265 \r
266    ASSERT(fd>=0);\r
267 \r
268    if (close(fd) == -1) my_fatal("my_close(): close(): %s\n",strerror(errno));\r
269 }\r
270 \r
271 // my_dup2()\r
272 \r
273 static void my_dup2(int old_fd, int new_fd) {\r
274 \r
275    ASSERT(old_fd>=0);\r
276    ASSERT(new_fd>=0);\r
277 \r
278    if (dup2(old_fd,new_fd) == -1) my_fatal("my_dup2(): dup2(): %s\n",strerror(errno));\r
279 }\r
280 \r
281 // end of posix part\r
282 #else\r
283 \r
284 // WIN32 part\r
285 \r
286 // includes\r
287 \r
288 #include <stdlib.h>\r
289 #include <string.h>\r
290 #include <windows.h>\r
291 #include <direct.h>\r
292 \r
293 \r
294 \r
295 #include "engine.h"\r
296 #include "option.h"\r
297 #include "pipe.h"\r
298 #include "posix.h"\r
299 \r
300 // constants\r
301 \r
302 static const int StringSize = 4096;\r
303 \r
304 // variables\r
305 \r
306 static int nQueuePtr = 0;\r
307 static char szQueueString[StringSize];\r
308 engine_t Engine[1];\r
309 \r
310 // functions\r
311 \r
312 DWORD GetWin32Priority(int nice)\r
313 {\r
314 /*\r
315 REALTIME_PRIORITY_CLASS     0x00000100\r
316 HIGH_PRIORITY_CLASS         0x00000080\r
317 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000\r
318 NORMAL_PRIORITY_CLASS       0x00000020\r
319 BELOW_NORMAL_PRIORITY_CLASS 0x00004000\r
320 IDLE_PRIORITY_CLASS         0x00000040\r
321 */\r
322         if (nice < -15) return 0x00000080;\r
323         if (nice < 0)   return 0x00008000;\r
324         if (nice == 0)  return 0x00000020;\r
325         if (nice < 15)  return 0x00004000;\r
326         return 0x00000040;\r
327 }\r
328 \r
329 \r
330 \r
331 void set_affinity(engine_t *engine, int affin){\r
332         if(affin==-1) return;\r
333     SetProcessAffinityMask((engine->pipeEngine).hProcess,affin);\r
334 }\r
335 \r
336 // Eric Mullins!\r
337 \r
338 void engine_set_nice_value(engine_t *engine, int value){\r
339     SetPriorityClass((engine->pipeEngine).hProcess,\r
340                      GetWin32Priority(value));\r
341 }\r
342 \r
343 \r
344 void engine_send_queue(engine_t * engine,const char *szFormat, ...) {\r
345   nQueuePtr += vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1));\r
346 }\r
347 \r
348 void engine_send(engine_t * engine, const char *szFormat, ...) {\r
349     vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1));\r
350     (engine->pipeEngine).LineOutput(szQueueString);\r
351     my_log("Adapter->Engine: %s\n",szQueueString);\r
352     nQueuePtr = 0;\r
353 }\r
354 \r
355 void engine_close(engine_t * engine){\r
356     char string[StringSize];\r
357     (engine->pipeEngine).Close();\r
358         // TODO: Timeout\r
359     while (!engine_eof(Engine)) {\r
360             engine_get(Engine,string,StringSize); \r
361         }\r
362     (engine->pipeEngine).Kill();\r
363 }\r
364 \r
365 \r
366 void engine_open(engine_t * engine){\r
367    int affinity;\r
368     char *my_dir;\r
369     engine->state=0;\r
370     if( (my_dir = _getcwd( NULL, 0 )) == NULL )\r
371         my_fatal("Can't build path: %s\n",strerror(errno));\r
372     SetCurrentDirectory(option_get_string("EngineDir"));\r
373     (engine->pipeEngine).Open(option_get_string("EngineCommand"));\r
374     if((engine->pipeEngine).Active()){\r
375         engine->state|=ENGINE_ACTIVE;\r
376             //play with affinity (bad idea)\r
377         affinity=option_get_int("Affinity");\r
378         if(affinity!=-1) set_affinity(engine,affinity); //AAA\r
379             //lets go back\r
380         SetCurrentDirectory(my_dir);\r
381             // set a low priority\r
382         if (option_get_bool("UseNice")){\r
383             my_log("POLYGLOT Adjust Engine Piority\n");\r
384             engine_set_nice_value(engine, option_get_int("NiceValue"));\r
385         }\r
386     }\r
387     \r
388 }\r
389 \r
390 bool engine_active(engine_t *engine){\r
391     return (engine->state & ENGINE_ACTIVE)!=0;\r
392 }\r
393 \r
394 bool engine_eof(engine_t *engine){\r
395     return (engine->state & ENGINE_EOF)!=0;\r
396 }\r
397 \r
398 bool engine_get_non_blocking(engine_t * engine, char *szLineStr, int size){\r
399     if(engine_eof(engine)){ return false;}\r
400         if ((engine->pipeEngine).LineInput(szLineStr)) {\r
401         my_log("Engine->Adapter: %s\n",szLineStr);\r
402         return true;\r
403     } else {\r
404         szLineStr[0]='\0';\r
405         if(engine->pipeEngine.EOF_()){\r
406             my_log("POLYGLOT EOF received from engine\n");\r
407             engine->state|=ENGINE_EOF;\r
408         }\r
409         return false;\r
410     }\r
411 }\r
412 \r
413 void engine_get(engine_t * engine, char *szLineStr, int size){\r
414     bool data_available;\r
415     if(engine_eof(engine))return;\r
416     while(true){\r
417         data_available=engine_get_non_blocking(engine,szLineStr,size);\r
418         if(!data_available && !engine_eof(engine)){\r
419             Idle();\r
420         }else{\r
421             break;\r
422         }\r
423     }\r
424 }\r
425 \r
426 \r
427 #endif\r