Mercurial > ~astiob > upreckon > hgweb
comparison upreckon/_unixmodule.cpp @ 146:d5b6708c1955
Distutils support, reorganization and cleaning up
* Removed command-line options -t and -u.
* Reorganized code:
o all modules are now in package upreckon;
o TestCaseNotPassed and its descendants now live in a separate
module exceptions;
o load_problem now lives in module problem.
* Commented out mentions of command-line option -c in --help.
* Added a distutils-based setup.py.
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Sat, 28 May 2011 14:24:25 +0100 |
parents | _unixmodule.cpp@f4361d557929 |
children | 9ed34ef740a1 |
comparison
equal
deleted
inserted
replaced
145:d2c266c8d820 | 146:d5b6708c1955 |
---|---|
1 // Copyright (c) 2011 Chortos-2 <chortos@inbox.lv> | |
2 | |
3 #include <Python.h> | |
4 #include <structmember.h> | |
5 #include <stdio.h> | |
6 | |
7 #ifdef HAVE_SYS_TYPES_H | |
8 #include <sys/types.h> | |
9 #endif | |
10 | |
11 #ifdef HAVE_FCNTL_H | |
12 #include <fcntl.h> | |
13 #endif | |
14 | |
15 #include <limits.h> | |
16 | |
17 #ifdef HAVE_SIGNAL_H | |
18 #include <signal.h> | |
19 #endif | |
20 | |
21 #ifdef HAVE_SPAWN_H | |
22 #include <spawn.h> | |
23 #ifdef __APPLE__ | |
24 #pragma weak_import posix_spawnp | |
25 #endif | |
26 #endif | |
27 | |
28 #ifdef HAVE_SYS_RESOURCE_H | |
29 #include <sys/resource.h> | |
30 #endif | |
31 | |
32 #ifdef HAVE_SYS_WAIT_H | |
33 #include <sys/wait.h> | |
34 #endif | |
35 | |
36 #ifdef HAVE_TERMIOS_H | |
37 #include <termios.h> | |
38 #endif | |
39 | |
40 #if !(defined __cplusplus) && !(defined bool) | |
41 #ifdef HAVE_C99_BOOL | |
42 #define bool _Bool | |
43 #else | |
44 #define bool char | |
45 #endif | |
46 #undef true | |
47 #define true 1 | |
48 #undef false | |
49 #define false 0 | |
50 #endif | |
51 | |
52 // On Python 2.5, SIGINT handling may get delayed until we return to Python | |
53 #if PY_MAJOR_VERSION > 2 || PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6 | |
54 #define USE_WAKEUP_FD | |
55 #endif | |
56 | |
57 #if !(defined RLIMIT_AS) && defined RLIMIT_VMEM | |
58 #define RLIMIT_AS RLIMIT_VMEM | |
59 #endif | |
60 | |
61 // Condition stolen from posixmodule.c of Python 2.7.1 | |
62 #if defined __USLC__ && defined __SCO_VERSION__ // SCO UDK Compiler | |
63 //#ifdef HAVE_FORK1 | |
64 #define fork fork1 | |
65 #endif | |
66 | |
67 // Stolen from posixmodule.c of Python 2.7.1 | |
68 #ifdef WITH_NEXT_FRAMEWORK | |
69 #include <crt_externs.h> | |
70 static char **environ = NULL; | |
71 #elif !(defined _MSC_VER) && (!(defined __WATCOMC__) || defined __QNX__) | |
72 extern char **environ; | |
73 #endif | |
74 | |
75 #ifndef Py_PYTIME_H | |
76 typedef struct timeval _PyTime_timeval; | |
77 #ifndef GETTIMEOFDAY_NO_TZ | |
78 #define _PyTime_gettimeofday(tvp) gettimeofday((tvp), NULL) | |
79 #else | |
80 #define _PyTime_gettimeofday(tvp) gettimeofday((tvp)) | |
81 #endif | |
82 #endif | |
83 | |
84 #if PY_MAJOR_VERSION >= 3 | |
85 #define PyInt_AsLong PyLong_AsLong | |
86 #define PyInt_FromLong PyLong_FromLong | |
87 #define PyNumber_Int PyNumber_Long | |
88 #endif | |
89 | |
90 #define TESTEE_SPAWNED 0 | |
91 #define TESTEE_SPAWN_FAILED 1 | |
92 #define TESTEE_REPORT_STATUS(status) \ | |
93 do \ | |
94 { \ | |
95 const char c = (status); \ | |
96 write(c2ppipe[1], &c, 1); \ | |
97 } \ | |
98 while (0) | |
99 | |
100 #if !(defined SIGKILL) && defined SIGTERM | |
101 #define SIGKILL SIGTERM | |
102 #endif | |
103 | |
104 #if defined HAVE_KILL && defined SIGKILL | |
105 #ifdef HAVE_WAITPID | |
106 #define TERM_TESTEE \ | |
107 do \ | |
108 { \ | |
109 kill(-curpid, SIGKILL); \ | |
110 kill(-curpid, SIGCONT); \ | |
111 while (waitpid(curpid, &retstat, 0) != curpid); \ | |
112 } \ | |
113 while (0) | |
114 #else | |
115 #define TERM_TESTEE \ | |
116 do \ | |
117 { \ | |
118 kill(-curpid, SIGKILL); \ | |
119 kill(-curpid, SIGCONT); \ | |
120 while (wait(&retstat) != curpid); \ | |
121 } \ | |
122 while (0) | |
123 #endif | |
124 #else | |
125 #define TERM_TESTEE | |
126 #endif | |
127 | |
128 #if defined HAVE_KILL && defined SIGINT | |
129 #define PROPAGATE_SIGINT ((void) kill(-curpid, SIGINT)) | |
130 #else | |
131 #define PROPAGATE_SIGINT | |
132 #endif | |
133 | |
134 struct child_stats | |
135 { | |
136 int returncode; | |
137 _PyTime_timeval walltime; | |
138 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 | |
139 _PyTime_timeval cputime; | |
140 Py_ssize_t memory; | |
141 #endif | |
142 }; | |
143 | |
144 static pid_t curpid; | |
145 static const struct child_stats zero_stats = { 0 }; | |
146 static PyObject *CannotStartTestee, *CanceledByUser, *WallTimeLimitExceeded, | |
147 *CPUTimeLimitExceeded, *MemoryLimitExceeded; | |
148 static _PyTime_timeval time_end; | |
149 | |
150 #ifdef USE_WAKEUP_FD | |
151 static char dont_care_buffer[512]; | |
152 static int intpipe[2] = { 0 }; | |
153 #endif | |
154 | |
155 #ifdef HAVE_TERMIOS_H | |
156 static bool catch_escape = false; | |
157 static struct termios orig_termios; | |
158 #endif | |
159 | |
160 typedef struct | |
161 { | |
162 PyObject_HEAD | |
163 int returncode; | |
164 } _unix__PopenPlaceholderObject; | |
165 | |
166 static PyMemberDef _PopenPlaceholder_members[] = | |
167 { | |
168 { "returncode", T_INT, offsetof(_unix__PopenPlaceholderObject, returncode), READONLY, NULL }, | |
169 { NULL } | |
170 }; | |
171 | |
172 static PyTypeObject _unix__PopenPlaceholderType = | |
173 { | |
174 #if PY_MAJOR_VERSION >= 3 | |
175 PyVarObject_HEAD_INIT(NULL, 0) | |
176 #else | |
177 PyObject_HEAD_INIT(NULL) | |
178 0, /*ob_size*/ | |
179 #endif | |
180 "_unix._PopenPlaceholder", /*tp_name*/ | |
181 sizeof(_unix__PopenPlaceholderObject), /*tp_basicsize*/ | |
182 0, /*tp_itemsize*/ | |
183 0, /*tp_dealloc*/ | |
184 0, /*tp_print*/ | |
185 0, /*tp_getattr*/ | |
186 0, /*tp_setattr*/ | |
187 0, /*tp_compare*/ | |
188 0, /*tp_repr*/ | |
189 0, /*tp_as_number*/ | |
190 0, /*tp_as_sequence*/ | |
191 0, /*tp_as_mapping*/ | |
192 0, /*tp_hash */ | |
193 0, /*tp_call*/ | |
194 0, /*tp_str*/ | |
195 0, /*tp_getattro*/ | |
196 0, /*tp_setattro*/ | |
197 0, /*tp_as_buffer*/ | |
198 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ | |
199 0, /*tp_doc*/ | |
200 0, /*tp_traverse*/ | |
201 0, /*tp_clear*/ | |
202 0, /*tp_richcompare*/ | |
203 0, /*tp_weaklistoffset*/ | |
204 0, /*tp_iter*/ | |
205 0, /*tp_iternext*/ | |
206 0, /*tp_methods*/ | |
207 _PopenPlaceholder_members, /*tp_members*/ | |
208 }; | |
209 | |
210 #ifndef timeradd | |
211 #define timeradd(a, b, res) \ | |
212 do \ | |
213 { \ | |
214 (res)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ | |
215 (res)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ | |
216 if ((res)->tv_usec >= 1000000) \ | |
217 { \ | |
218 ++(res)->tv_sec; \ | |
219 (res)->tv_usec -= 1000000; \ | |
220 } \ | |
221 } \ | |
222 while (0) | |
223 #endif | |
224 | |
225 #ifndef timersub | |
226 #define timersub(a, b, res) \ | |
227 do \ | |
228 { \ | |
229 (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ | |
230 (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ | |
231 if ((res)->tv_usec < 0) \ | |
232 { \ | |
233 --(res)->tv_sec; \ | |
234 (res)->tv_usec += 1000000; \ | |
235 } \ | |
236 } \ | |
237 while (0) | |
238 #endif | |
239 | |
240 #ifndef timerclear | |
241 #define timerclear(tvp) ((void) ((tvp)->tv_sec = (tvp)->tv_usec = 0)) | |
242 #endif | |
243 | |
244 #ifndef timerisset | |
245 #define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) | |
246 #endif | |
247 | |
248 #ifndef timercmp | |
249 #define timercmp(a, b, cmp) \ | |
250 (((a)->tv_sec == (b)->tv_sec) \ | |
251 ? ((a)->tv_usec cmp (b)->tv_usec) \ | |
252 : ((a)->tv_sec cmp (b)->tv_sec)) | |
253 #endif | |
254 | |
255 // Stolen from posixmodule.c of Python 2.7.1 | |
256 static void free_string_array(char **array, Py_ssize_t count) | |
257 { | |
258 Py_ssize_t i; | |
259 for (i = 0; i < count; ++i) | |
260 PyMem_Free(array[i]); | |
261 PyMem_DEL(array); | |
262 } | |
263 | |
264 // Stolen from termios.c of Python 2.7.1 | |
265 static int fdconv(PyObject *obj, void *p) | |
266 { | |
267 int fd = PyObject_AsFileDescriptor(obj); | |
268 if (fd >= 0) | |
269 { | |
270 *((int *) p) = fd; | |
271 return 1; | |
272 } | |
273 return 0; | |
274 } | |
275 | |
276 // Parts stolen from bltinmodule.c, posixmodule.c and termios.c of Python 2.7.1 | |
277 static int my_spawn(PyObject *args, PyObject *kwds, int c2ppipe[2], int maxcputime, Py_ssize_t maxmemory) | |
278 { | |
279 static const char *const kwlist[] = { "stdin", "stdout", "stderr", NULL }; | |
280 static PyObject *dummy_args = NULL; | |
281 Py_ssize_t i, argc; | |
282 char **argv; | |
283 bool own_args = false; | |
284 int fdin = 0, fdout = 1, fderr = 2; | |
285 | |
286 if (dummy_args == NULL) | |
287 { | |
288 if (!(dummy_args = PyTuple_New(0))) | |
289 { | |
290 return -1; | |
291 } | |
292 } | |
293 | |
294 if (!PyArg_ParseTuple(args, "O:call", &args)) | |
295 { | |
296 return -1; | |
297 } | |
298 if (!PyArg_ParseTupleAndKeywords(dummy_args, kwds, "|O&O&O&:call", (char **) kwlist, fdconv, &fdin, fdconv, &fdout, fdconv, &fderr)) | |
299 { | |
300 return -1; | |
301 } | |
302 | |
303 #if PY_MAJOR_VERSION >= 3 | |
304 if (PyUnicode_Check(args)) | |
305 #else | |
306 if (PyString_Check(args) || PyUnicode_Check(args)) | |
307 #endif | |
308 { | |
309 argc = 1; | |
310 args = PyTuple_Pack(1, args); | |
311 if (args == NULL) | |
312 { | |
313 return -1; | |
314 } | |
315 own_args = true; | |
316 } | |
317 else if (!PySequence_Check(args)) | |
318 { | |
319 PyErr_SetString(PyExc_TypeError, "call() argument must be a sequence or string"); | |
320 return -1; | |
321 } | |
322 else | |
323 { | |
324 argc = PySequence_Size(args); | |
325 if (argc < 1) | |
326 { | |
327 PyErr_SetString(PyExc_TypeError, "call() argument must not be empty"); | |
328 return -1; | |
329 } | |
330 } | |
331 | |
332 argv = PyMem_NEW(char *, argc + 1); | |
333 if (argv == NULL) | |
334 { | |
335 if (own_args) | |
336 { | |
337 Py_DECREF(args); | |
338 } | |
339 PyErr_NoMemory(); | |
340 return -1; | |
341 } | |
342 | |
343 for (i = 0; i < argc; ++i) | |
344 { | |
345 if (!PyArg_Parse(PySequence_ITEM(args, i), "et", Py_FileSystemDefaultEncoding, &argv[i])) | |
346 { | |
347 free_string_array(argv, i); | |
348 if (own_args) | |
349 { | |
350 Py_DECREF(args); | |
351 } | |
352 PyErr_SetString(PyExc_TypeError, "call() argument must contain only strings"); | |
353 return -1; | |
354 } | |
355 } | |
356 argv[argc] = NULL; | |
357 | |
358 curpid = fork(); | |
359 if (!curpid) | |
360 { | |
361 pid_t pid; | |
362 int spawn_errno, status, fd, fddupped[3]; | |
363 struct child_stats stats; | |
364 _PyTime_timeval tvstart, tvend; | |
365 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 | |
366 struct rusage rusage; | |
367 #endif | |
368 #if defined RLIMIT_AS || defined RLIMIT_CPU | |
369 struct rlimit rlimit; | |
370 #endif | |
371 | |
372 /* | |
373 Assume no errors occur: | |
374 * POSIX:2008 doesn't even define any errors for setpgrp, | |
375 nor does the (probably copied-verbatim-from-FreeBSD) man page | |
376 on Mac OS X 10.6; | |
377 * none of the error conditions POSIX:2008 does define | |
378 for setpgid can occur. | |
379 */ | |
380 #ifdef HAVE_SETPGID | |
381 setpgid(0, 0); | |
382 #else //if defined HAVE_SETPGRP | |
383 #ifdef SETPGRP_HAVE_ARG | |
384 setpgrp(0, 0); | |
385 #else | |
386 setpgrp(); | |
387 #endif | |
388 #endif | |
389 | |
390 #ifdef SIGINT | |
391 signal(SIGINT, SIG_DFL); | |
392 #endif | |
393 | |
394 #if PY_MAJOR_VERSION > 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2 | |
395 _Py_RestoreSignals(); | |
396 #else | |
397 #ifdef SIGPIPE | |
398 signal(SIGPIPE, SIG_DFL); | |
399 #endif | |
400 #ifdef SIGXFSZ | |
401 signal(SIGXFSZ, SIG_DFL); | |
402 #endif | |
403 #ifdef SIGXFZ | |
404 signal(SIGXFZ, SIG_DFL); | |
405 #endif | |
406 #endif | |
407 | |
408 if (c2ppipe[1] < 3) | |
409 { | |
410 int newfd; | |
411 #ifdef F_DUPFD_CLOEXEC | |
412 newfd = fcntl(c2ppipe[1], F_DUPFD_CLOEXEC, 3); | |
413 if (newfd == -1) | |
414 { | |
415 spawn_errno = errno; | |
416 TESTEE_REPORT_STATUS(TESTEE_SPAWN_FAILED); | |
417 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); | |
418 _exit(127); | |
419 } | |
420 c2ppipe[1] = newfd; | |
421 #else | |
422 newfd = fcntl(c2ppipe[1], F_DUPFD, 3); | |
423 // Other threads should not fork/spawn right now | |
424 if (newfd == -1 | |
425 || fcntl(newfd, F_SETFD, fcntl(newfd, F_GETFD) | FD_CLOEXEC) == -1) | |
426 { | |
427 spawn_errno = errno; | |
428 TESTEE_REPORT_STATUS(TESTEE_SPAWN_FAILED); | |
429 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); | |
430 _exit(127); | |
431 } | |
432 c2ppipe[1] = newfd; | |
433 #endif | |
434 } | |
435 // Yes, this works as intended even if fdin == fdout == fderr == 0 | |
436 // and there are no open file descriptors except 0 and c2ppipe | |
437 // FIXME: error handling | |
438 fddupped[0] = dup(fdin); | |
439 fddupped[1] = dup(fdout); | |
440 fddupped[2] = dup(fderr); | |
441 dup2(fddupped[0], 0); | |
442 dup2(fddupped[1], 1); | |
443 dup2(fddupped[2], 2); | |
444 // FIXME: close() may fail with EINTR or EIO; is setting CLOEXEC safer? | |
445 // Bear in mind we still want to close them in _this_ process | |
446 for (fd = sysconf(_SC_OPEN_MAX); --fd > c2ppipe[1]; ) | |
447 { | |
448 close(fd); | |
449 } | |
450 while (--fd >= 3) | |
451 { | |
452 close(fd); | |
453 } | |
454 | |
455 #ifdef RLIMIT_AS | |
456 if (maxmemory) | |
457 { | |
458 rlimit.rlim_cur = rlimit.rlim_max = maxmemory; | |
459 setrlimit(RLIMIT_AS, &rlimit); | |
460 } | |
461 #endif | |
462 #ifdef RLIMIT_CPU | |
463 if (maxcputime) | |
464 { | |
465 rlimit.rlim_cur = rlimit.rlim_max = maxcputime; | |
466 setrlimit(RLIMIT_CPU, &rlimit); | |
467 } | |
468 #endif | |
469 | |
470 #ifdef HAVE_SPAWN_H | |
471 #ifdef __APPLE__ | |
472 if (posix_spawnp != NULL) | |
473 { | |
474 #endif | |
475 spawn_errno = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ); | |
476 _PyTime_gettimeofday(&tvstart); | |
477 | |
478 if (spawn_errno) | |
479 { | |
480 TESTEE_REPORT_STATUS(TESTEE_SPAWN_FAILED); | |
481 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); | |
482 _exit(127); | |
483 } | |
484 #ifdef __APPLE__ | |
485 } | |
486 else | |
487 #endif | |
488 #endif | |
489 #if !(defined HAVE_SPAWN_H) || defined __APPLE__ | |
490 { | |
491 pid = fork(); | |
492 if (!pid) | |
493 { | |
494 execvp(argv[0], argv); | |
495 spawn_errno = errno; | |
496 TESTEE_REPORT_STATUS(TESTEE_SPAWN_FAILED); | |
497 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); | |
498 _exit(127); | |
499 } | |
500 else if (pid == -1) | |
501 { | |
502 spawn_errno = errno; | |
503 TESTEE_REPORT_STATUS(TESTEE_SPAWN_FAILED); | |
504 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); | |
505 _exit(127); | |
506 } | |
507 else | |
508 { | |
509 _PyTime_gettimeofday(&tvstart); | |
510 } | |
511 } | |
512 #endif | |
513 TESTEE_REPORT_STATUS(TESTEE_SPAWNED); | |
514 write(c2ppipe[1], &tvstart, sizeof tvstart); | |
515 | |
516 #ifdef HAVE_WAIT4 | |
517 while (wait4(pid, &status, 0, &rusage) != pid); | |
518 #elif defined HAVE_WAIT3 | |
519 while (wait3(&status, 0, &rusage) != pid); | |
520 #elif defined HAVE_WAITPID | |
521 while (waitpid(pid, &status, 0) != pid); | |
522 #else | |
523 while (wait(&status) != pid); | |
524 #endif | |
525 | |
526 _PyTime_gettimeofday(&tvend); | |
527 #if defined HAVE_SYS_RESOURCE_H && !(defined HAVE_WAIT4 || defined HAVE_WAIT3) | |
528 getrusage(RUSAGE_CHILDREN, &rusage); | |
529 #endif | |
530 | |
531 stats = zero_stats; | |
532 | |
533 if (WIFEXITED(status) && WEXITSTATUS(status) == 127) _exit(127); | |
534 else if (WIFSIGNALED(status)) stats.returncode = -WTERMSIG(status); | |
535 else stats.returncode = WEXITSTATUS(status); | |
536 | |
537 timersub(&tvend, &tvstart, &stats.walltime); | |
538 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 | |
539 timeradd(&rusage.ru_utime, &rusage.ru_stime, &stats.cputime); | |
540 #ifdef __APPLE__ | |
541 stats.memory = rusage.ru_maxrss; | |
542 #else | |
543 stats.memory = rusage.ru_maxrss << 10; | |
544 #endif | |
545 #endif | |
546 | |
547 write(c2ppipe[1], &stats, sizeof stats); | |
548 _exit(0); | |
549 } | |
550 else if (curpid == -1) | |
551 { | |
552 PyErr_SetFromErrno(PyExc_OSError); | |
553 free_string_array(argv, argc); | |
554 if (own_args) | |
555 { | |
556 Py_DECREF(args); | |
557 } | |
558 return 0; | |
559 } | |
560 | |
561 /* | |
562 Assume no errors occur if the child is still alive: | |
563 * the (probably copied-verbatim-from-FreeBSD) man page | |
564 on Mac OS X 10.6 doesn't even define any errors for setpgrp; | |
565 * none of the error conditions POSIX:2008 defines | |
566 for setpgid can occur. | |
567 */ | |
568 #ifdef HAVE_SETPGID | |
569 setpgid(curpid, 0); | |
570 #elif defined SETPGRP_HAVE_ARG | |
571 setpgrp(curpid, 0); | |
572 #endif | |
573 | |
574 free_string_array(argv, argc); | |
575 if (own_args) | |
576 { | |
577 Py_DECREF(args); | |
578 } | |
579 return 1; | |
580 } | |
581 | |
582 static inline bool attr_to_timeval(PyObject *obj, const char *attr, _PyTime_timeval *ptv) | |
583 { | |
584 #ifdef HAVE_LONG_LONG | |
585 long long i_whole; | |
586 #else | |
587 long i_whole; | |
588 #endif | |
589 PyObject *whole, *frac, *million, *usec, *usec_whole; | |
590 PyObject *member = PyObject_GetAttrString(obj, attr); | |
591 if (member == NULL) | |
592 { | |
593 return false; | |
594 } | |
595 if (member == Py_None) | |
596 { | |
597 Py_DECREF(member); | |
598 timerclear(ptv); | |
599 return true; | |
600 } | |
601 whole = PyNumber_Int(member); | |
602 if (whole == NULL) | |
603 { | |
604 Py_DECREF(member); | |
605 return false; | |
606 } | |
607 #ifdef HAVE_LONG_LONG | |
608 i_whole = PyLong_AsLongLong(whole); | |
609 #else | |
610 i_whole = PyInt_AsLong(whole); | |
611 #endif | |
612 if (i_whole == -1 && PyErr_Occurred() != NULL) | |
613 { | |
614 Py_DECREF(whole); | |
615 Py_DECREF(member); | |
616 return false; | |
617 } | |
618 // FIXME: detect time_t overflow | |
619 ptv->tv_sec = i_whole; | |
620 frac = PyNumber_Subtract(member, whole); | |
621 Py_DECREF(whole); | |
622 Py_DECREF(member); | |
623 if (frac == NULL) | |
624 { | |
625 return false; | |
626 } | |
627 million = PyInt_FromLong(1000000); | |
628 if (million == NULL) | |
629 { | |
630 Py_DECREF(frac); | |
631 return false; | |
632 } | |
633 usec = PyNumber_InPlaceMultiply(frac, million); | |
634 Py_DECREF(million); | |
635 Py_DECREF(frac); | |
636 if (usec == NULL) | |
637 { | |
638 return false; | |
639 } | |
640 usec_whole = PyNumber_Int(usec); | |
641 Py_DECREF(usec); | |
642 if (usec_whole == NULL) | |
643 { | |
644 return false; | |
645 } | |
646 // FIXME: a sanity check (0 <= value < 1000000) here wouldn't harm | |
647 ptv->tv_usec = PyInt_AsLong(usec_whole); | |
648 Py_DECREF(usec_whole); | |
649 return ptv->tv_usec != -1 || PyErr_Occurred() == NULL; | |
650 } | |
651 | |
652 #ifdef __cplusplus | |
653 typedef struct { char a[2]; } two_chars; | |
654 static char is_int(char); | |
655 static char is_int(signed char); | |
656 static char is_int(unsigned char); | |
657 static char is_int(short); | |
658 static char is_int(unsigned short); | |
659 static char is_int(int); | |
660 static char is_int(unsigned); | |
661 static char is_int(long); | |
662 static char is_int(unsigned long); | |
663 #ifdef HAVE_LONG_LONG | |
664 static char is_int(long long); | |
665 static char is_int(unsigned long long); | |
666 #endif | |
667 static two_chars is_int(...); | |
668 #endif | |
669 | |
670 static inline bool timeval_to_attr(_PyTime_timeval *ptv, PyObject *obj, const char *attr) | |
671 { | |
672 PyObject *value; | |
673 #ifdef __cplusplus | |
674 // If tv_sec has an integral type and !tv_usec, try to create a Python int | |
675 if (sizeof is_int(ptv->tv_sec) == sizeof(char) && !ptv->tv_usec) | |
676 { | |
677 if (ptv->tv_sec <= LONG_MAX) | |
678 { | |
679 value = PyInt_FromLong(ptv->tv_sec); | |
680 } | |
681 // FIXME: signed/unsigned comparisons ruin everything | |
682 #ifdef HAVE_LONG_LONG | |
683 else// if (ptv->tv_sec <= ULLONG_MAX) | |
684 { | |
685 value = PyLong_FromUnsignedLongLong(ptv->tv_sec); | |
686 } | |
687 #else | |
688 // else if (ptv->tv_sec <= ULONG_MAX) | |
689 // { | |
690 // value = PyLong_FromUnsignedLong(ptv->tv_sec); | |
691 // } | |
692 //#endif | |
693 else | |
694 { | |
695 value = PyFloat_FromDouble(ptv->tv_sec); | |
696 } | |
697 // | |
698 #endif | |
699 // | |
700 } | |
701 else | |
702 #endif | |
703 { | |
704 // TODO: use decimal.Decimal or fractions.Fraction | |
705 value = PyFloat_FromDouble(ptv->tv_sec + ptv->tv_usec * 0.000001); | |
706 } | |
707 if (value == NULL) | |
708 { | |
709 return false; | |
710 } | |
711 if (PyObject_SetAttrString(obj, attr, value) == -1) | |
712 { | |
713 return false; | |
714 } | |
715 Py_DECREF(value); | |
716 return true; | |
717 } | |
718 | |
719 /* | |
720 TODO/FIXME: | |
721 * Replace timeval->timespec and select->pselect if pselect is available | |
722 (preferably only if pselect is not a wrapper around select). | |
723 * File descriptors might be >= FD_SETSIZE? | |
724 */ | |
725 static PyObject *_unix_call(PyObject *self, PyObject *args, PyObject *kwds) | |
726 { | |
727 PyObject *testcase = NULL, *obj; | |
728 _unix__PopenPlaceholderObject *Popen_placeholder; | |
729 int spawn_errno = 0, spawn_status, s, c2ppipe[2], retstat; | |
730 struct child_stats stats = zero_stats; | |
731 _PyTime_timeval maxwalltime, maxcputime, timeout, time_start; | |
732 Py_ssize_t maxmemory, r; | |
733 size_t stats_read = 0; | |
734 fd_set readfds; | |
735 char c; | |
736 bool have_maxwalltime; | |
737 | |
738 if (kwds != NULL) | |
739 { | |
740 testcase = PyDict_GetItemString(kwds, "case"); | |
741 } | |
742 if (testcase == NULL) | |
743 { | |
744 PyErr_SetString(PyExc_TypeError, "call() requires a keyword argument 'case'"); | |
745 return NULL; | |
746 } | |
747 Py_INCREF(testcase); | |
748 PyDict_DelItemString(kwds, "case"); | |
749 | |
750 if (!attr_to_timeval(testcase, "maxwalltime", &maxwalltime) | |
751 || !attr_to_timeval(testcase, "maxcputime", &maxcputime)) | |
752 { | |
753 Py_DECREF(testcase); | |
754 return NULL; | |
755 } | |
756 | |
757 obj = PyObject_GetAttrString(testcase, "maxmemory"); | |
758 if (obj == NULL) | |
759 { | |
760 Py_DECREF(testcase); | |
761 return NULL; | |
762 } | |
763 if (PyObject_IsTrue(obj)) | |
764 { | |
765 PyObject *factor, *bytes; | |
766 factor = PyInt_FromLong(1024 * 1024); | |
767 if (factor == NULL) | |
768 { | |
769 Py_DECREF(testcase); | |
770 return NULL; | |
771 } | |
772 bytes = PyNumber_Multiply(obj, factor); | |
773 Py_DECREF(factor); | |
774 if (bytes == NULL) | |
775 { | |
776 Py_DECREF(testcase); | |
777 return NULL; | |
778 } | |
779 maxmemory = PyNumber_AsSsize_t(bytes, PyExc_OverflowError); | |
780 Py_DECREF(bytes); | |
781 if (maxmemory == -1 && PyErr_Occurred() != NULL) | |
782 { | |
783 Py_DECREF(testcase); | |
784 return NULL; | |
785 } | |
786 } | |
787 else | |
788 { | |
789 maxmemory = 0; | |
790 } | |
791 Py_DECREF(obj); | |
792 | |
793 #ifdef HAVE_PIPE2 | |
794 if (pipe2(c2ppipe, O_CLOEXEC)) | |
795 { | |
796 PyErr_SetFromErrno(PyExc_IOError); | |
797 Py_DECREF(testcase); | |
798 return NULL; | |
799 } | |
800 #else | |
801 if (pipe(c2ppipe)) | |
802 { | |
803 PyErr_SetFromErrno(PyExc_IOError); | |
804 Py_DECREF(testcase); | |
805 return NULL; | |
806 } | |
807 // Does any other thread fork/spawn right now? Please shoot it in the head | |
808 // (well, if this ends up causing trouble, anyway) | |
809 if (fcntl(c2ppipe[0], F_SETFD, fcntl(c2ppipe[0], F_GETFD) | FD_CLOEXEC) == -1 | |
810 || fcntl(c2ppipe[1], F_SETFD, fcntl(c2ppipe[1], F_GETFD) | FD_CLOEXEC) == -1) | |
811 { | |
812 PyErr_SetFromErrno(PyExc_IOError); | |
813 close(c2ppipe[0]); | |
814 close(c2ppipe[1]); | |
815 Py_DECREF(testcase); | |
816 return NULL; | |
817 } | |
818 #endif | |
819 | |
820 spawn_status = my_spawn(args, kwds, c2ppipe, maxcputime.tv_sec + (maxcputime.tv_usec > 0), maxmemory); | |
821 close(c2ppipe[1]); | |
822 if (!spawn_status) | |
823 { | |
824 PyObject *type, *value, *traceback, *e; | |
825 close(c2ppipe[0]); | |
826 Py_DECREF(testcase); | |
827 PyErr_Fetch(&type, &value, &traceback); | |
828 PyErr_NormalizeException(&type, &value, &traceback); | |
829 Py_XDECREF(traceback); | |
830 Py_DECREF(type); | |
831 e = PyObject_CallFunctionObjArgs(CannotStartTestee, value, NULL); | |
832 Py_DECREF(value); | |
833 PyErr_SetObject(CannotStartTestee, e); | |
834 Py_DECREF(e); | |
835 return NULL; | |
836 } | |
837 else if (spawn_status < 0) | |
838 { | |
839 close(c2ppipe[0]); | |
840 Py_DECREF(testcase); | |
841 return NULL; | |
842 } | |
843 | |
844 // FIXME: use select in order not to miss SIGINT | |
845 while ((r = read(c2ppipe[0], &c, 1)) == -1 && errno == EINTR) | |
846 { | |
847 if (PyErr_CheckSignals() == -1) | |
848 { | |
849 PROPAGATE_SIGINT; | |
850 close(c2ppipe[0]); | |
851 Py_DECREF(testcase); | |
852 TERM_TESTEE; | |
853 return NULL; | |
854 } | |
855 } | |
856 if (r == 1) | |
857 { | |
858 if (c == TESTEE_SPAWNED) | |
859 { | |
860 size_t got = 0; | |
861 while (got < sizeof time_start) | |
862 { | |
863 r = read(c2ppipe[0], got + (char *) &time_start, sizeof time_start - got); | |
864 if (r > 0) | |
865 { | |
866 got += r; | |
867 } | |
868 else if (!r) | |
869 { | |
870 errno = 0; | |
871 PyErr_SetFromErrno(PyExc_IOError); | |
872 goto spawn_failed; | |
873 } | |
874 else if (errno == EINTR) | |
875 { | |
876 if (PyErr_CheckSignals() == -1) | |
877 { | |
878 PROPAGATE_SIGINT; | |
879 close(c2ppipe[0]); | |
880 Py_DECREF(testcase); | |
881 TERM_TESTEE; | |
882 return NULL; | |
883 } | |
884 } | |
885 else | |
886 { | |
887 PyErr_SetFromErrno(PyExc_IOError); | |
888 goto spawn_failed; | |
889 } | |
890 } | |
891 if (!timeval_to_attr(&time_start, testcase, "time_started")) | |
892 { | |
893 close(c2ppipe[0]); | |
894 Py_DECREF(testcase); | |
895 TERM_TESTEE; | |
896 return NULL; | |
897 } | |
898 } | |
899 else // if (c == TESTEE_SPAWN_FAILED) | |
900 { | |
901 size_t got = 0; | |
902 while (got < sizeof spawn_errno) | |
903 { | |
904 r = read(c2ppipe[0], got + (char *) &spawn_errno, sizeof spawn_errno - got); | |
905 if (r > 0) | |
906 { | |
907 got += r; | |
908 } | |
909 else if (!r) | |
910 { | |
911 // Can't get the real error; use zero instead | |
912 spawn_errno = 0; | |
913 break; | |
914 } | |
915 else if (errno == EINTR) | |
916 { | |
917 if (PyErr_CheckSignals() == -1) | |
918 { | |
919 PROPAGATE_SIGINT; | |
920 close(c2ppipe[0]); | |
921 Py_DECREF(testcase); | |
922 TERM_TESTEE; | |
923 return NULL; | |
924 } | |
925 } | |
926 else | |
927 { | |
928 PyErr_SetFromErrno(PyExc_IOError); | |
929 goto spawn_failed; | |
930 } | |
931 } | |
932 errno = spawn_errno; | |
933 /* | |
934 if (errno == EACCES || errno == EINVAL || errno == ELOOP | |
935 || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR | |
936 || errno == ENOEXEC || errno == ETXTBSY) | |
937 { | |
938 PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, PySequence_ITEM(args, 0)); | |
939 } | |
940 else | |
941 {*/ | |
942 PyErr_SetFromErrno(PyExc_OSError); | |
943 //} | |
944 goto spawn_failed; | |
945 } | |
946 } | |
947 else | |
948 { | |
949 PyObject *type, *value, *traceback, *e; | |
950 if (!r) errno = 0; | |
951 PyErr_SetFromErrno(PyExc_IOError); | |
952 spawn_failed: | |
953 Py_DECREF(testcase); | |
954 close(c2ppipe[0]); | |
955 TERM_TESTEE; | |
956 PyErr_Fetch(&type, &value, &traceback); | |
957 PyErr_NormalizeException(&type, &value, &traceback); | |
958 Py_XDECREF(traceback); | |
959 Py_DECREF(type); | |
960 e = PyObject_CallFunctionObjArgs(CannotStartTestee, value, NULL); | |
961 Py_DECREF(value); | |
962 PyErr_SetObject(CannotStartTestee, e); | |
963 Py_DECREF(e); | |
964 return NULL; | |
965 } | |
966 | |
967 Py_BEGIN_ALLOW_THREADS | |
968 timeradd(&time_start, &maxwalltime, &time_end); | |
969 FD_ZERO(&readfds); | |
970 have_maxwalltime = timerisset(&maxwalltime); | |
971 /* | |
972 Implementations may place limitations on the maximum timeout | |
973 interval supported. All implementations shall support a maximum | |
974 timeout interval of at least 31 days. If the timeout argument | |
975 specifies a timeout interval greater than the implementation- | |
976 defined maximum value, the maximum value shall be used as the | |
977 actual timeout value. | |
978 (POSIX:2008) | |
979 Therefore the loop and the && timercmp(&time_end, &now, <). | |
980 */ | |
981 for (;;) | |
982 { | |
983 _PyTime_timeval now; | |
984 int maxfd = c2ppipe[0]; | |
985 #ifdef HAVE_TERMIOS_H | |
986 if (catch_escape) FD_SET(0, &readfds); | |
987 #endif | |
988 #ifdef USE_WAKEUP_FD | |
989 FD_SET(intpipe[0], &readfds); | |
990 if (intpipe[0] > maxfd) maxfd = intpipe[0]; | |
991 #endif | |
992 FD_SET(c2ppipe[0], &readfds); | |
993 | |
994 if (have_maxwalltime) | |
995 { | |
996 _PyTime_gettimeofday(&now); | |
997 if (timercmp(&time_end, &now, <)) | |
998 { | |
999 timerclear(&timeout); | |
1000 } | |
1001 else | |
1002 { | |
1003 timersub(&time_end, &now, &timeout); | |
1004 } | |
1005 | |
1006 s = select(maxfd + 1, &readfds, NULL, NULL, &timeout); | |
1007 | |
1008 if (!s && timercmp(&time_end, &now, <)) | |
1009 { | |
1010 close(c2ppipe[0]); | |
1011 TERM_TESTEE; | |
1012 Py_BLOCK_THREADS | |
1013 Py_DECREF(testcase); | |
1014 PyErr_SetObject(WallTimeLimitExceeded, NULL); | |
1015 return NULL; | |
1016 } | |
1017 } | |
1018 else | |
1019 { | |
1020 s = select(maxfd + 1, &readfds, NULL, NULL, NULL); | |
1021 } | |
1022 | |
1023 if (s < 0 && errno == EINTR) | |
1024 { | |
1025 Py_BLOCK_THREADS | |
1026 if (PyErr_CheckSignals() == -1) | |
1027 { | |
1028 PROPAGATE_SIGINT; | |
1029 close(c2ppipe[0]); | |
1030 Py_DECREF(testcase); | |
1031 TERM_TESTEE; | |
1032 return NULL; | |
1033 } | |
1034 Py_UNBLOCK_THREADS | |
1035 } | |
1036 else if (s < 0 && errno != EAGAIN) | |
1037 { | |
1038 Py_BLOCK_THREADS | |
1039 PyErr_SetFromErrno(PyExc_IOError); | |
1040 close(c2ppipe[0]); | |
1041 Py_DECREF(testcase); | |
1042 TERM_TESTEE; | |
1043 return NULL; | |
1044 } | |
1045 #ifdef USE_WAKEUP_FD | |
1046 else if (s > 0 && FD_ISSET(intpipe[0], &readfds)) | |
1047 { | |
1048 // FIXME: is error handling needed? | |
1049 while (read(intpipe[0], dont_care_buffer, sizeof dont_care_buffer) > 0); | |
1050 Py_BLOCK_THREADS | |
1051 if (PyErr_CheckSignals() == -1) | |
1052 { | |
1053 PROPAGATE_SIGINT; | |
1054 close(c2ppipe[0]); | |
1055 Py_DECREF(testcase); | |
1056 TERM_TESTEE; | |
1057 return NULL; | |
1058 } | |
1059 Py_UNBLOCK_THREADS | |
1060 } | |
1061 #endif | |
1062 #ifdef HAVE_TERMIOS_H | |
1063 else if (s > 0 && !FD_ISSET(c2ppipe[0], &readfds)) | |
1064 { | |
1065 // FIXME: is error and EOF handling needed? | |
1066 if ((r = read(0, &c, 1)) == 1) | |
1067 { | |
1068 if (c == '\33') | |
1069 { | |
1070 close(c2ppipe[0]); | |
1071 TERM_TESTEE; | |
1072 Py_BLOCK_THREADS | |
1073 Py_DECREF(testcase); | |
1074 PyErr_SetObject(CanceledByUser, NULL); | |
1075 return NULL; | |
1076 } | |
1077 } | |
1078 else if (r == -1 && errno == EINTR) | |
1079 { | |
1080 if (PyErr_CheckSignals() == -1) | |
1081 { | |
1082 PROPAGATE_SIGINT; | |
1083 close(c2ppipe[0]); | |
1084 Py_DECREF(testcase); | |
1085 TERM_TESTEE; | |
1086 return NULL; | |
1087 } | |
1088 } | |
1089 } | |
1090 #endif | |
1091 else if (s > 0) | |
1092 { | |
1093 bool blocked_threads = false; | |
1094 while ((r = read(c2ppipe[0], stats_read + (char *) &stats, sizeof stats - stats_read)) == -1 && errno == EINTR) | |
1095 { | |
1096 Py_BLOCK_THREADS | |
1097 blocked_threads = true; | |
1098 if (PyErr_CheckSignals() == -1) | |
1099 { | |
1100 PROPAGATE_SIGINT; | |
1101 close(c2ppipe[0]); | |
1102 Py_DECREF(testcase); | |
1103 TERM_TESTEE; | |
1104 return NULL; | |
1105 } | |
1106 } | |
1107 if (r > 0) | |
1108 { | |
1109 stats_read += r; | |
1110 } | |
1111 else if (!r) | |
1112 { | |
1113 break; | |
1114 } | |
1115 else | |
1116 { | |
1117 close(c2ppipe[0]); | |
1118 TERM_TESTEE; | |
1119 if (!blocked_threads) | |
1120 { | |
1121 Py_BLOCK_THREADS | |
1122 } | |
1123 Py_DECREF(testcase); | |
1124 PyErr_SetFromErrno(PyExc_IOError); | |
1125 return NULL; | |
1126 } | |
1127 if (blocked_threads) | |
1128 { | |
1129 Py_UNBLOCK_THREADS | |
1130 } | |
1131 } | |
1132 } | |
1133 close(c2ppipe[0]); | |
1134 Py_END_ALLOW_THREADS | |
1135 | |
1136 #ifdef HAVE_WAITPID | |
1137 while (waitpid(curpid, &retstat, 0) != curpid) | |
1138 #else | |
1139 while (wait(&retstat) != curpid) | |
1140 #endif | |
1141 { | |
1142 if (PyErr_CheckSignals() == -1) | |
1143 { | |
1144 Py_DECREF(testcase); | |
1145 return NULL; | |
1146 } | |
1147 } | |
1148 | |
1149 if (WIFEXITED(retstat) && WEXITSTATUS(retstat) == 127) | |
1150 { | |
1151 PyObject *type, *value, *traceback, *e; | |
1152 Py_DECREF(testcase); | |
1153 errno = 0; | |
1154 PyErr_SetFromErrno(PyExc_OSError); | |
1155 PyErr_Fetch(&type, &value, &traceback); | |
1156 PyErr_NormalizeException(&type, &value, &traceback); | |
1157 Py_XDECREF(traceback); | |
1158 Py_DECREF(type); | |
1159 e = PyObject_CallFunctionObjArgs(CannotStartTestee, value, NULL); | |
1160 Py_DECREF(value); | |
1161 PyErr_SetObject(CannotStartTestee, e); | |
1162 Py_DECREF(e); | |
1163 return NULL; | |
1164 } | |
1165 else if (!WIFEXITED(retstat) || WEXITSTATUS(retstat)) | |
1166 { | |
1167 Py_DECREF(testcase); | |
1168 if (WIFSTOPPED(retstat)) | |
1169 { | |
1170 return PyErr_Format(PyExc_EnvironmentError, "unexpected exit status from worker: stopped by signal %d", WSTOPSIG(retstat)); | |
1171 } | |
1172 else if (WIFSIGNALED(retstat)) | |
1173 { | |
1174 return PyErr_Format(PyExc_EnvironmentError, "unexpected exit status from worker: terminated by signal %d", WTERMSIG(retstat)); | |
1175 } | |
1176 else if (WIFEXITED(retstat)) | |
1177 { | |
1178 return PyErr_Format(PyExc_EnvironmentError, "unexpected exit status from worker: %d", WEXITSTATUS(retstat)); | |
1179 } | |
1180 else | |
1181 { | |
1182 PyErr_SetString(PyExc_EnvironmentError, "unexpected exit status from worker: not exited, signaled or stopped"); | |
1183 return NULL; | |
1184 } | |
1185 } | |
1186 | |
1187 if (stats_read != sizeof stats) | |
1188 { | |
1189 Py_DECREF(testcase); | |
1190 PyErr_SetString(PyExc_EnvironmentError, "unexpectedly early end of output from worker"); | |
1191 return NULL; | |
1192 } | |
1193 | |
1194 if (timerisset(&maxwalltime) && timercmp(&stats.walltime, &maxwalltime, >)) | |
1195 { | |
1196 Py_DECREF(testcase); | |
1197 PyErr_SetObject(WallTimeLimitExceeded, NULL); | |
1198 return NULL; | |
1199 } | |
1200 | |
1201 obj = PyInt_FromLong(0); | |
1202 if (obj == NULL) | |
1203 { | |
1204 Py_DECREF(testcase); | |
1205 return NULL; | |
1206 } | |
1207 if (PyObject_SetAttrString(testcase, "time_started", obj) == -1) | |
1208 { | |
1209 Py_DECREF(testcase); | |
1210 return NULL; | |
1211 } | |
1212 Py_DECREF(obj); | |
1213 | |
1214 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 | |
1215 if (timerisset(&maxcputime) || !timerisset(&maxwalltime)) | |
1216 { | |
1217 PyObject *cputls; | |
1218 if (!timeval_to_attr(&stats.cputime, testcase, "time_stopped")) | |
1219 { | |
1220 Py_DECREF(testcase); | |
1221 return NULL; | |
1222 } | |
1223 cputls = PyObject_GetAttrString(testcase, "cpu_time_limit_string"); | |
1224 if (cputls == NULL) | |
1225 { | |
1226 Py_DECREF(testcase); | |
1227 return NULL; | |
1228 } | |
1229 if (PyObject_SetAttrString(testcase, "time_limit_string", cputls) == -1) | |
1230 { | |
1231 Py_DECREF(testcase); | |
1232 return NULL; | |
1233 } | |
1234 Py_DECREF(cputls); | |
1235 if (timerisset(&maxcputime) && timercmp(&stats.cputime, &maxcputime, >)) | |
1236 { | |
1237 Py_DECREF(testcase); | |
1238 PyErr_SetObject(CPUTimeLimitExceeded, NULL); | |
1239 return NULL; | |
1240 } | |
1241 } | |
1242 else | |
1243 #endif | |
1244 { | |
1245 if (!timeval_to_attr(&stats.walltime, testcase, "time_stopped")) | |
1246 { | |
1247 Py_DECREF(testcase); | |
1248 return NULL; | |
1249 } | |
1250 } | |
1251 | |
1252 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 | |
1253 if (maxmemory && stats.memory > maxmemory) | |
1254 { | |
1255 Py_DECREF(testcase); | |
1256 PyErr_SetObject(MemoryLimitExceeded, NULL); | |
1257 return NULL; | |
1258 } | |
1259 #endif | |
1260 | |
1261 Popen_placeholder = PyObject_New(_unix__PopenPlaceholderObject, &_unix__PopenPlaceholderType); | |
1262 if (Popen_placeholder == NULL) | |
1263 { | |
1264 return NULL; | |
1265 } | |
1266 Popen_placeholder->returncode = stats.returncode; | |
1267 PyObject_SetAttrString(testcase, "process", (PyObject *) Popen_placeholder); | |
1268 Py_DECREF(Popen_placeholder); | |
1269 Py_DECREF(testcase); | |
1270 Py_RETURN_NONE; | |
1271 } | |
1272 | |
1273 static PyObject *_unix_pause(PyObject *self) | |
1274 { | |
1275 #ifdef HAVE_TERMIOS_H | |
1276 if (catch_escape) | |
1277 { | |
1278 char c; | |
1279 while (read(0, &c, 1) == -1 && errno == EINTR); | |
1280 } | |
1281 #endif | |
1282 Py_RETURN_NONE; | |
1283 } | |
1284 | |
1285 static PyMethodDef _unixMethods[] = | |
1286 { | |
1287 { "call", (PyCFunction) _unix_call, METH_VARARGS | METH_KEYWORDS, "Call a process." }, | |
1288 { "pause", (PyCFunction) _unix_pause, METH_NOARGS, "Block until a key is pressed." }, | |
1289 { NULL } | |
1290 }; | |
1291 | |
1292 #ifdef USE_WAKEUP_FD | |
1293 static void close_intpipe(void) | |
1294 { | |
1295 close(intpipe[0]); | |
1296 close(intpipe[1]); | |
1297 intpipe[0] = intpipe[1] = 0; | |
1298 } | |
1299 #endif | |
1300 | |
1301 #ifdef HAVE_TERMIOS_H | |
1302 static void restore_termios(void) | |
1303 { | |
1304 tcsetattr(0, TCSAFLUSH, &orig_termios); | |
1305 #ifdef USE_WAKEUP_FD | |
1306 close_intpipe(); | |
1307 #endif | |
1308 } | |
1309 #endif | |
1310 | |
1311 #if PY_MAJOR_VERSION >= 3 | |
1312 #define INIT_FAIL return NULL | |
1313 static PyModuleDef _unixmodule = | |
1314 { | |
1315 PyModuleDef_HEAD_INIT, | |
1316 "_unix", | |
1317 NULL, | |
1318 -1, | |
1319 _unixMethods | |
1320 }; | |
1321 | |
1322 PyMODINIT_FUNC PyInit__unix(void) | |
1323 #else | |
1324 #define INIT_FAIL return | |
1325 PyMODINIT_FUNC init_unix(void) | |
1326 #endif | |
1327 { | |
1328 struct termios new_termios; | |
1329 PyObject *exceptions; | |
1330 | |
1331 _unix__PopenPlaceholderType.tp_new = PyType_GenericNew; | |
1332 if (PyType_Ready(&_unix__PopenPlaceholderType) == -1) | |
1333 { | |
1334 INIT_FAIL; | |
1335 } | |
1336 | |
1337 exceptions = PyImport_ImportModule("upreckon.exceptions"); | |
1338 if (exceptions == NULL | |
1339 || (CannotStartTestee = PyObject_GetAttrString(exceptions, "CannotStartTestee")) == NULL | |
1340 || (CanceledByUser = PyObject_GetAttrString(exceptions, "CanceledByUser")) == NULL | |
1341 || (WallTimeLimitExceeded = PyObject_GetAttrString(exceptions, "WallTimeLimitExceeded")) == NULL | |
1342 || (CPUTimeLimitExceeded = PyObject_GetAttrString(exceptions, "CPUTimeLimitExceeded")) == NULL | |
1343 || (MemoryLimitExceeded = PyObject_GetAttrString(exceptions, "MemoryLimitExceeded")) == NULL) | |
1344 { | |
1345 Py_XDECREF(MemoryLimitExceeded); | |
1346 Py_XDECREF(CPUTimeLimitExceeded); | |
1347 Py_XDECREF(WallTimeLimitExceeded); | |
1348 Py_XDECREF(CanceledByUser); | |
1349 Py_XDECREF(CannotStartTestee); | |
1350 Py_XDECREF(exceptions); | |
1351 INIT_FAIL; | |
1352 } | |
1353 Py_DECREF(exceptions); | |
1354 | |
1355 #ifdef WITH_NEXT_FRAMEWORK | |
1356 if (environ == NULL) | |
1357 { | |
1358 environ = *_NSGetEnviron(); | |
1359 } | |
1360 #endif | |
1361 | |
1362 #ifdef USE_WAKEUP_FD | |
1363 if (!intpipe[0] || !intpipe[1]) | |
1364 { | |
1365 #ifdef HAVE_PIPE2 | |
1366 if (pipe2(intpipe, O_CLOEXEC | O_NONBLOCK)) | |
1367 { | |
1368 PyErr_SetFromErrno(PyExc_IOError); | |
1369 Py_DECREF(MemoryLimitExceeded); | |
1370 Py_DECREF(CPUTimeLimitExceeded); | |
1371 Py_DECREF(WallTimeLimitExceeded); | |
1372 Py_DECREF(CanceledByUser); | |
1373 Py_DECREF(CannotStartTestee); | |
1374 INIT_FAIL; | |
1375 } | |
1376 #else | |
1377 if (pipe(intpipe)) | |
1378 { | |
1379 PyErr_SetFromErrno(PyExc_IOError); | |
1380 Py_DECREF(MemoryLimitExceeded); | |
1381 Py_DECREF(CPUTimeLimitExceeded); | |
1382 Py_DECREF(WallTimeLimitExceeded); | |
1383 Py_DECREF(CanceledByUser); | |
1384 Py_DECREF(CannotStartTestee); | |
1385 INIT_FAIL; | |
1386 } | |
1387 // Other threads must not fork now | |
1388 if (fcntl(intpipe[0], F_SETFD, fcntl(intpipe[0], F_GETFD) | FD_CLOEXEC) == -1 | |
1389 || fcntl(intpipe[1], F_SETFD, fcntl(intpipe[1], F_GETFD) | FD_CLOEXEC) == -1 | |
1390 || fcntl(intpipe[0], F_SETFL, fcntl(intpipe[0], F_GETFL) | O_NONBLOCK) == -1 | |
1391 || fcntl(intpipe[1], F_SETFL, fcntl(intpipe[1], F_GETFL) | O_NONBLOCK) == -1) | |
1392 { | |
1393 PyErr_SetFromErrno(PyExc_IOError); | |
1394 close(intpipe[0]); | |
1395 close(intpipe[1]); | |
1396 Py_DECREF(MemoryLimitExceeded); | |
1397 Py_DECREF(CPUTimeLimitExceeded); | |
1398 Py_DECREF(WallTimeLimitExceeded); | |
1399 Py_DECREF(CanceledByUser); | |
1400 Py_DECREF(CannotStartTestee); | |
1401 INIT_FAIL; | |
1402 } | |
1403 #endif | |
1404 } | |
1405 | |
1406 PySignal_SetWakeupFd(intpipe[1]); | |
1407 #endif | |
1408 | |
1409 #ifdef HAVE_TERMIOS_H | |
1410 if (!tcgetattr(0, &orig_termios)) | |
1411 { | |
1412 new_termios = orig_termios; | |
1413 // Stolen from tty.py of Python 2.7.1 | |
1414 new_termios.c_lflag &= ~(ECHO | ICANON); | |
1415 new_termios.c_cc[VMIN] = 1; | |
1416 new_termios.c_cc[VTIME] = 0; | |
1417 if (!Py_AtExit(restore_termios) && !tcsetattr(0, TCSAFLUSH, &new_termios)) | |
1418 { | |
1419 catch_escape = true; | |
1420 } | |
1421 } | |
1422 #ifdef USE_WAKEUP_FD | |
1423 else | |
1424 { | |
1425 Py_AtExit(close_intpipe); | |
1426 } | |
1427 #endif | |
1428 #elif defined USE_WAKEUP_FD | |
1429 Py_AtExit(close_intpipe); | |
1430 #endif | |
1431 | |
1432 PyObject *module; | |
1433 #if PY_MAJOR_VERSION >= 3 | |
1434 module = PyModule_Create(&_unixmodule); | |
1435 #else | |
1436 module = Py_InitModule("_unix", _unixMethods); | |
1437 #endif | |
1438 if (module == NULL) | |
1439 { | |
1440 Py_DECREF(MemoryLimitExceeded); | |
1441 Py_DECREF(CPUTimeLimitExceeded); | |
1442 Py_DECREF(WallTimeLimitExceeded); | |
1443 Py_DECREF(CanceledByUser); | |
1444 Py_DECREF(CannotStartTestee); | |
1445 } | |
1446 #if PY_MAJOR_VERSION >= 3 | |
1447 return module; | |
1448 #endif | |
1449 } |