version 1.4w10UCIb22
[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 unsigned 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_non_blocking()\r
204 \r
205 bool engine_get_non_blocking(engine_t * engine, char string[], int size){\r
206     if(io_line_ready(engine->io)){\r
207         engine_get(engine,string,StringSize);\r
208         return true;\r
209     }else{\r
210         string[0]='\0';\r
211         return false;\r
212     }\r
213 }\r
214 \r
215 // engine_get()\r
216 \r
217 void engine_get(engine_t * engine, char string[], int size) {\r
218 \r
219    ASSERT(engine_is_ok(engine));\r
220    ASSERT(string!=NULL);\r
221    ASSERT(size>=256);\r
222 \r
223    while (!io_line_ready(engine->io)) {\r
224       io_get_update(engine->io);\r
225    }\r
226 \r
227    if (!io_get_line(engine->io,string,size)) { // EOF\r
228        engine->state|=ENGINE_EOF;\r
229    }\r
230 }\r
231 \r
232 // engine_send()\r
233 \r
234 void engine_send(engine_t * engine, const char format[], ...) {\r
235 \r
236    va_list arg_list;\r
237    char string[StringSize];\r
238 \r
239    ASSERT(engine_is_ok(engine));\r
240    ASSERT(format!=NULL);\r
241 \r
242    // format\r
243 \r
244    va_start(arg_list,format);\r
245    vsprintf(string,format,arg_list);\r
246    va_end(arg_list);\r
247 \r
248    // send\r
249 \r
250    io_send(engine->io,"%s",string);\r
251 }\r
252 \r
253 // engine_send_queue()\r
254 \r
255 void engine_send_queue(engine_t * engine, const char format[], ...) {\r
256 \r
257    va_list arg_list;\r
258    char string[StringSize];\r
259 \r
260    ASSERT(engine_is_ok(engine));\r
261    ASSERT(format!=NULL);\r
262 \r
263    // format\r
264 \r
265    va_start(arg_list,format);\r
266    vsprintf(string,format,arg_list);\r
267    va_end(arg_list);\r
268 \r
269    // send\r
270 \r
271    io_send_queue(engine->io,"%s",string);\r
272 }\r
273 \r
274 // my_close()\r
275 \r
276 static void my_close(int fd) {\r
277 \r
278    ASSERT(fd>=0);\r
279 \r
280    if (close(fd) == -1) my_fatal("my_close(): close(): %s\n",strerror(errno));\r
281 }\r
282 \r
283 // my_dup2()\r
284 \r
285 static void my_dup2(int old_fd, int new_fd) {\r
286 \r
287    ASSERT(old_fd>=0);\r
288    ASSERT(new_fd>=0);\r
289 \r
290    if (dup2(old_fd,new_fd) == -1) my_fatal("my_dup2(): dup2(): %s\n",strerror(errno));\r
291 }\r
292 \r
293 // end of posix part\r
294 #else\r
295 \r
296 // WIN32 part\r
297 \r
298 // includes\r
299 \r
300 #include <stdlib.h>\r
301 #include <string.h>\r
302 #include <windows.h>\r
303 #include <direct.h>\r
304 \r
305 \r
306 \r
307 #include "engine.h"\r
308 #include "option.h"\r
309 #include "pipe.h"\r
310 #include "posix.h"\r
311 \r
312 // constants\r
313 \r
314 static const int StringSize = 4096;\r
315 \r
316 // variables\r
317 \r
318 static int nQueuePtr = 0;\r
319 static char szQueueString[StringSize];\r
320 engine_t Engine[1];\r
321 \r
322 // functions\r
323 \r
324 DWORD GetWin32Priority(int nice)\r
325 {\r
326 /*\r
327 REALTIME_PRIORITY_CLASS     0x00000100\r
328 HIGH_PRIORITY_CLASS         0x00000080\r
329 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000\r
330 NORMAL_PRIORITY_CLASS       0x00000020\r
331 BELOW_NORMAL_PRIORITY_CLASS 0x00004000\r
332 IDLE_PRIORITY_CLASS         0x00000040\r
333 */\r
334         if (nice < -15) return 0x00000080;\r
335         if (nice < 0)   return 0x00008000;\r
336         if (nice == 0)  return 0x00000020;\r
337         if (nice < 15)  return 0x00004000;\r
338         return 0x00000040;\r
339 }\r
340 \r
341 \r
342 \r
343 void set_affinity(engine_t *engine, int affin){\r
344         if(affin==-1) return;\r
345     SetProcessAffinityMask((engine->io).hProcess,affin);\r
346 }\r
347 \r
348 // Eric Mullins!\r
349 \r
350 void engine_set_nice_value(engine_t *engine, int value){\r
351     SetPriorityClass((engine->io).hProcess,\r
352                      GetWin32Priority(value));\r
353 }\r
354 \r
355 \r
356 void engine_send_queue(engine_t * engine,const char *szFormat, ...) {\r
357     nQueuePtr += vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1));\r
358 }\r
359 \r
360 void engine_send(engine_t * engine, const char *szFormat, ...) {\r
361     vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1));\r
362     (engine->io).LineOutput(szQueueString);\r
363     my_log("Adapter->Engine: %s\n",szQueueString);\r
364     nQueuePtr = 0;\r
365 }\r
366 \r
367 void engine_close(engine_t * engine){\r
368     char string[StringSize];\r
369     (engine->io).Close();\r
370         // TODO: Timeout\r
371     while (!engine_eof(Engine)) { \r
372         engine_get_non_blocking(Engine,string,StringSize);\r
373         Idle();\r
374     }\r
375     (engine->io).Kill();\r
376 }\r
377 \r
378 \r
379 void engine_open(engine_t * engine){\r
380     int affinity;\r
381     char *my_dir;\r
382     engine->state=0;\r
383     if( (my_dir = _getcwd( NULL, 0 )) == NULL )\r
384         my_fatal("Can't build path: %s\n",strerror(errno));\r
385     SetCurrentDirectory(option_get_string("EngineDir"));\r
386     (engine->io).Open(option_get_string("EngineCommand"));\r
387     if((engine->io).Active()){\r
388         engine->state|=ENGINE_ACTIVE;\r
389             //play with affinity (bad idea)\r
390         affinity=option_get_int("Affinity");\r
391         if(affinity!=-1) set_affinity(engine,affinity); //AAA\r
392             //lets go back\r
393         SetCurrentDirectory(my_dir);\r
394             // set a low priority\r
395         if (option_get_bool("UseNice")){\r
396             my_log("POLYGLOT Adjust Engine Piority\n");\r
397             engine_set_nice_value(engine, option_get_int("NiceValue"));\r
398         }\r
399     }\r
400     \r
401 }\r
402 \r
403 bool engine_active(engine_t *engine){\r
404     return (engine->state & ENGINE_ACTIVE)!=0;\r
405 }\r
406 \r
407 bool engine_eof(engine_t *engine){\r
408     return (engine->state & ENGINE_EOF)!=0;\r
409 }\r
410 \r
411 bool engine_get_non_blocking(engine_t * engine, char *szLineStr, int size){\r
412     if(engine_eof(engine)){ return false;}\r
413         if ((engine->io).GetBuffer(szLineStr)) {\r
414         my_log("Engine->Adapter: %s\n",szLineStr);\r
415         return true;\r
416     } else {\r
417         szLineStr[0]='\0';\r
418         if(engine->io.EOF_()){\r
419             engine->state|=ENGINE_EOF;\r
420         }\r
421         return false;\r
422     }\r
423 }\r
424 \r
425 void engine_get(engine_t * engine, char *szLineStr, int size){\r
426     (engine->io).LineInput(szLineStr);\r
427     if(engine->io.EOF_()){\r
428         engine->state|=ENGINE_EOF;\r
429     }\r
430 }\r
431 \r
432 \r
433 #endif\r