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