blob: 9c5df16e156a1df280a4d4581dd870c227a1a6ca [file] [log] [blame]
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001/* _interpreters module */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002/* low-level access to interpreter primitives */
3
4#include "Python.h"
5#include "frameobject.h"
Eric Snowc11183c2019-03-15 16:35:46 -06006#include "interpreteridobject.h"
Eric Snow7f8bfc92018-01-29 18:23:44 -07007
8
Eric Snowa1d9e0a2020-05-07 08:56:01 -06009// XXX Emit a warning?
10#define IGNORE_FAILURE(msg) \
11 fprintf(stderr, " -----\nRunFailedError: %s\n", msg); \
12 PyErr_PrintEx(0); \
13 fprintf(stderr, " -----\n"); \
14 PyErr_Clear();
15
16typedef void (*_deallocfunc)(void *);
Eric Snow4e9da0d2018-02-02 21:49:49 -070017
Eric Snow7f8bfc92018-01-29 18:23:44 -070018static PyInterpreterState *
19_get_current(void)
20{
Eric Snowa1d9e0a2020-05-07 08:56:01 -060021 // _PyInterpreterState_Get() aborts if lookup fails, so don't need
Eric Snow7f8bfc92018-01-29 18:23:44 -070022 // to check the result for NULL.
Eric Snowa1d9e0a2020-05-07 08:56:01 -060023 return _PyInterpreterState_Get();
24}
25
26
27/* string utils *************************************************************/
28
29// PyMem_Free() must be used to dealocate the resulting string.
30static char *
31_strdup_and_size(const char *data, Py_ssize_t *psize, _deallocfunc *dealloc)
32{
33 if (data == NULL) {
34 if (psize != NULL) {
35 *psize = 0;
36 }
37 if (dealloc != NULL) {
38 *dealloc = NULL;
39 }
40 return "";
41 }
42
43 Py_ssize_t size;
44 if (psize == NULL) {
45 size = strlen(data);
46 } else {
47 size = *psize;
48 if (size == 0) {
49 size = strlen(data);
50 *psize = size; // The size "return" value.
51 }
52 }
53 char *copied = PyMem_Malloc(size+1);
54 if (copied == NULL) {
55 PyErr_NoMemory();
56 return NULL;
57 }
58 if (dealloc != NULL) {
59 *dealloc = PyMem_Free;
60 }
61 memcpy(copied, data, size+1);
62 return copied;
63}
64
65static const char *
66_pyobj_get_str_and_size(PyObject *obj, Py_ssize_t *psize)
67{
68 if (PyUnicode_Check(obj)) {
69 return PyUnicode_AsUTF8AndSize(obj, psize);
70 } else {
71 const char *data = NULL;
72 PyBytes_AsStringAndSize(obj, (char **)&data, psize);
73 return data;
74 }
75}
76
77/* "raw" strings */
78
79typedef struct _rawstring {
80 Py_ssize_t size;
81 const char *data;
82 _deallocfunc dealloc;
83} _rawstring;
84
85static void
86_rawstring_init(_rawstring *raw)
87{
88 raw->size = 0;
89 raw->data = NULL;
90 raw->dealloc = NULL;
91}
92
93static _rawstring *
94_rawstring_new(void)
95{
96 _rawstring *raw = PyMem_NEW(_rawstring, 1);
97 if (raw == NULL) {
98 PyErr_NoMemory();
99 return NULL;
100 }
101 _rawstring_init(raw);
102 return raw;
103}
104
105static void
106_rawstring_clear(_rawstring *raw)
107{
108 if (raw->data != NULL && raw->dealloc != NULL) {
109 (*raw->dealloc)((void *)raw->data);
110 }
111 _rawstring_init(raw);
112}
113
114static void
115_rawstring_free(_rawstring *raw)
116{
117 _rawstring_clear(raw);
118 PyMem_Free(raw);
119}
120
121static int
122_rawstring_is_clear(_rawstring *raw)
123{
124 return raw->size == 0 && raw->data == NULL && raw->dealloc == NULL;
125}
126
127//static void
128//_rawstring_move(_rawstring *raw, _rawstring *src)
129//{
130// raw->size = src->size;
131// raw->data = src->data;
132// raw->dealloc = src->dealloc;
133// _rawstring_init(src);
134//}
135
136static void
137_rawstring_proxy(_rawstring *raw, const char *str)
138{
139 if (str == NULL) {
140 str = "";
141 }
142 raw->size = strlen(str);
143 raw->data = str;
144 raw->dealloc = NULL;
145}
146
147static int
148_rawstring_buffer(_rawstring *raw, Py_ssize_t size)
149{
150 raw->data = PyMem_Malloc(size+1);
151 if (raw->data == NULL) {
152 PyErr_NoMemory();
153 return -1;
154 }
155 raw->size = size;
156 raw->dealloc = PyMem_Free;
157 return 0;
158}
159
160static int
161_rawstring_strcpy(_rawstring *raw, const char *str, Py_ssize_t size)
162{
163 _deallocfunc dealloc = NULL;
164 const char *copied = _strdup_and_size(str, &size, &dealloc);
165 if (copied == NULL) {
166 return -1;
167 }
168
169 raw->size = size;
170 raw->dealloc = dealloc;
171 raw->data = copied;
172 return 0;
173}
174
175static int
176_rawstring_from_pyobj(_rawstring *raw, PyObject *obj)
177{
178 Py_ssize_t size = 0;
179 const char *data = _pyobj_get_str_and_size(obj, &size);
180 if (PyErr_Occurred()) {
181 return -1;
182 }
183 if (_rawstring_strcpy(raw, data, size) != 0) {
184 return -1;
185 }
186 return 0;
187}
188
189static int
190_rawstring_from_pyobj_attr(_rawstring *raw, PyObject *obj, const char *attr)
191{
192 int res = -1;
193 PyObject *valueobj = PyObject_GetAttrString(obj, attr);
194 if (valueobj == NULL) {
195 goto done;
196 }
197 if (!PyUnicode_Check(valueobj)) {
198 // XXX PyObject_Str()? Repr()?
199 goto done;
200 }
201 const char *valuestr = PyUnicode_AsUTF8(valueobj);
202 if (valuestr == NULL) {
203 if (PyErr_Occurred()) {
204 goto done;
205 }
206 } else if (_rawstring_strcpy(raw, valuestr, 0) != 0) {
207 _rawstring_clear(raw);
208 goto done;
209 }
210 res = 0;
211
212done:
213 Py_XDECREF(valueobj);
214 return res;
215}
216
217static PyObject *
218_rawstring_as_pybytes(_rawstring *raw)
219{
220 return PyBytes_FromStringAndSize(raw->data, raw->size);
221}
222
223
224/* object utils *************************************************************/
225
226static void
227_pyobj_identify_type(PyObject *obj, _rawstring *modname, _rawstring *clsname)
228{
229 PyObject *objtype = (PyObject *)Py_TYPE(obj);
230
231 // Try __module__ and __name__.
232 if (_rawstring_from_pyobj_attr(modname, objtype, "__module__") != 0) {
233 // Fall back to the previous values in "modname".
234 IGNORE_FAILURE("bad __module__");
235 }
236 if (_rawstring_from_pyobj_attr(clsname, objtype, "__name__") != 0) {
237 // Fall back to the previous values in "clsname".
238 IGNORE_FAILURE("bad __name__");
239 }
240
241 // XXX Fall back to __qualname__?
242 // XXX Fall back to tp_name?
243}
244
245static PyObject *
246_pyobj_get_class(const char *modname, const char *clsname)
247{
248 assert(clsname != NULL);
249 if (modname == NULL) {
250 modname = "builtins";
251 }
252
253 PyObject *module = PyImport_ImportModule(modname);
254 if (module == NULL) {
255 return NULL;
256 }
257 PyObject *cls = PyObject_GetAttrString(module, clsname);
258 Py_DECREF(module);
259 return cls;
260}
261
262static PyObject *
263_pyobj_create(const char *modname, const char *clsname, PyObject *arg)
264{
265 PyObject *cls = _pyobj_get_class(modname, clsname);
266 if (cls == NULL) {
267 return NULL;
268 }
269 PyObject *obj = NULL;
270 if (arg == NULL) {
271 obj = _PyObject_CallNoArg(cls);
272 } else {
273 obj = PyObject_CallFunction(cls, "O", arg);
274 }
275 Py_DECREF(cls);
276 return obj;
277}
278
279
280/* object snapshots */
281
282typedef struct _objsnapshot {
283 // If modname is NULL then try "builtins" and "__main__".
284 _rawstring modname;
285 // clsname is required.
286 _rawstring clsname;
287
288 // The rest are optional.
289
290 // The serialized exception.
291 _rawstring *serialized;
292} _objsnapshot;
293
294static void
295_objsnapshot_init(_objsnapshot *osn)
296{
297 _rawstring_init(&osn->modname);
298 _rawstring_init(&osn->clsname);
299 osn->serialized = NULL;
300}
301
302//static _objsnapshot *
303//_objsnapshot_new(void)
304//{
305// _objsnapshot *osn = PyMem_NEW(_objsnapshot, 1);
306// if (osn == NULL) {
307// PyErr_NoMemory();
308// return NULL;
309// }
310// _objsnapshot_init(osn);
311// return osn;
312//}
313
314static void
315_objsnapshot_clear(_objsnapshot *osn)
316{
317 _rawstring_clear(&osn->modname);
318 _rawstring_clear(&osn->clsname);
319 if (osn->serialized != NULL) {
320 _rawstring_free(osn->serialized);
321 osn->serialized = NULL;
322 }
323}
324
325//static void
326//_objsnapshot_free(_objsnapshot *osn)
327//{
328// _objsnapshot_clear(osn);
329// PyMem_Free(osn);
330//}
331
332static int
333_objsnapshot_is_clear(_objsnapshot *osn)
334{
335 return osn->serialized == NULL
336 && _rawstring_is_clear(&osn->modname)
337 && _rawstring_is_clear(&osn->clsname);
338}
339
340static void
341_objsnapshot_summarize(_objsnapshot *osn, _rawstring *rawbuf, const char *msg)
342{
343 if (msg == NULL || *msg == '\0') {
344 // XXX Keep it NULL?
345 // XXX Keep it an empty string?
346 // XXX Use something more informative?
347 msg = "<no message>";
348 }
349 const char *clsname = osn->clsname.data;
350 const char *modname = osn->modname.data;
351 if (modname && *modname == '\0') {
352 modname = NULL;
353 }
354
355 // Prep the buffer.
356 Py_ssize_t size = strlen(clsname);
357 if (modname != NULL) {
358 if (strcmp(modname, "builtins") == 0) {
359 modname = NULL;
360 } else if (strcmp(modname, "__main__") == 0) {
361 modname = NULL;
362 } else {
363 size += strlen(modname) + 1;
364 }
365 }
366 if (msg != NULL) {
367 size += strlen(": ") + strlen(msg);
368 }
369 if (modname != NULL || msg != NULL) {
370 if (_rawstring_buffer(rawbuf, size) != 0) {
371 IGNORE_FAILURE("could not summarize object snapshot");
372 return;
373 }
374 }
375 // ...else we'll proxy clsname as-is, so no need to allocate a buffer.
376
377 // XXX Use __qualname__ somehow?
378 char *buf = (char *)rawbuf->data;
379 if (modname != NULL) {
380 if (msg != NULL) {
381 snprintf(buf, size+1, "%s.%s: %s", modname, clsname, msg);
382 } else {
383 snprintf(buf, size+1, "%s.%s", modname, clsname);
384 }
385 } else if (msg != NULL) {
386 snprintf(buf, size+1, "%s: %s", clsname, msg);
387 } else {
388 _rawstring_proxy(rawbuf, clsname);
389 }
390}
391
392static _rawstring *
393_objsnapshot_get_minimal_summary(_objsnapshot *osn, PyObject *obj)
394{
395 const char *str = NULL;
396 PyObject *objstr = PyObject_Str(obj);
397 if (objstr == NULL) {
398 PyErr_Clear();
399 } else {
400 str = PyUnicode_AsUTF8(objstr);
401 if (str == NULL) {
402 PyErr_Clear();
403 }
404 }
405
406 _rawstring *summary = _rawstring_new();
407 if (summary == NULL) {
408 return NULL;
409 }
410 _objsnapshot_summarize(osn, summary, str);
411 return summary;
412}
413
414static void
415_objsnapshot_extract(_objsnapshot *osn, PyObject *obj)
416{
417 assert(_objsnapshot_is_clear(osn));
418
419 // Get the "qualname".
420 _rawstring_proxy(&osn->modname, "<unknown>");
421 _rawstring_proxy(&osn->clsname, "<unknown>");
422 _pyobj_identify_type(obj, &osn->modname, &osn->clsname);
423
424 // Serialize the object.
425 // XXX Use marshal?
426 PyObject *pickle = PyImport_ImportModule("pickle");
427 if (pickle == NULL) {
428 IGNORE_FAILURE("could not serialize object: pickle import failed");
429 return;
430 }
431 PyObject *objdata = PyObject_CallMethod(pickle, "dumps", "(O)", obj);
432 Py_DECREF(pickle);
433 if (objdata == NULL) {
434 IGNORE_FAILURE("could not serialize object: pickle.dumps failed");
435 } else {
436 _rawstring *serialized = _rawstring_new();
437 int res = _rawstring_from_pyobj(serialized, objdata);
438 Py_DECREF(objdata);
439 if (res != 0) {
440 IGNORE_FAILURE("could not serialize object: raw str failed");
441 _rawstring_free(serialized);
442 } else if (serialized->size == 0) {
443 _rawstring_free(serialized);
444 } else {
445 osn->serialized = serialized;
446 }
447 }
448}
449
450static PyObject *
451_objsnapshot_resolve_serialized(_objsnapshot *osn)
452{
453 assert(osn->serialized != NULL);
454
455 // XXX Use marshal?
456 PyObject *pickle = PyImport_ImportModule("pickle");
457 if (pickle == NULL) {
458 return NULL;
459 }
460 PyObject *objdata = _rawstring_as_pybytes(osn->serialized);
461 if (objdata == NULL) {
462 return NULL;
463 } else {
464 PyObject *obj = PyObject_CallMethod(pickle, "loads", "O", objdata);
465 Py_DECREF(objdata);
466 return obj;
467 }
468}
469
470static PyObject *
471_objsnapshot_resolve_naive(_objsnapshot *osn, PyObject *arg)
472{
473 if (_rawstring_is_clear(&osn->clsname)) {
474 // We can't proceed without at least the class name.
475 PyErr_SetString(PyExc_ValueError, "missing class name");
476 return NULL;
477 }
478
479 if (osn->modname.data != NULL) {
480 return _pyobj_create(osn->modname.data, osn->clsname.data, arg);
481 } else {
482 PyObject *obj = _pyobj_create("builtins", osn->clsname.data, arg);
483 if (obj == NULL) {
484 PyErr_Clear();
485 obj = _pyobj_create("__main__", osn->clsname.data, arg);
486 }
487 return obj;
488 }
489}
490
491static PyObject *
492_objsnapshot_resolve(_objsnapshot *osn)
493{
494 if (osn->serialized != NULL) {
495 PyObject *obj = _objsnapshot_resolve_serialized(osn);
496 if (obj != NULL) {
497 return obj;
498 }
499 IGNORE_FAILURE("could not de-serialize object");
500 }
501
502 // Fall back to naive resolution.
503 return _objsnapshot_resolve_naive(osn, NULL);
504}
505
506
507/* exception utils **********************************************************/
508
509// _pyexc_create is inspired by _PyErr_SetObject().
510
511static PyObject *
512_pyexc_create(PyObject *exctype, const char *msg, PyObject *tb)
513{
514 assert(exctype != NULL && PyExceptionClass_Check(exctype));
515
516 PyObject *curtype = NULL, *curexc = NULL, *curtb = NULL;
517 PyErr_Fetch(&curtype, &curexc, &curtb);
518
519 // Create the object.
520 PyObject *exc = NULL;
521 if (msg != NULL) {
522 PyObject *msgobj = PyUnicode_FromString(msg);
523 if (msgobj == NULL) {
524 IGNORE_FAILURE("could not deserialize propagated error message");
525 }
526 exc = _PyObject_CallOneArg(exctype, msgobj);
527 Py_XDECREF(msgobj);
528 } else {
529 exc = _PyObject_CallNoArg(exctype);
530 }
531 if (exc == NULL) {
532 return NULL;
533 }
534
535 // Set the traceback, if any.
536 if (tb == NULL) {
537 tb = curtb;
538 }
539 if (tb != NULL) {
540 // This does *not* steal a reference!
541 PyException_SetTraceback(exc, tb);
542 }
543
544 PyErr_Restore(curtype, curexc, curtb);
545
546 return exc;
547}
548
549/* traceback snapshots */
550
551typedef struct _tbsnapshot {
552 _rawstring tbs_funcname;
553 _rawstring tbs_filename;
554 int tbs_lineno;
555 struct _tbsnapshot *tbs_next;
556} _tbsnapshot;
557
558static void
559_tbsnapshot_init(_tbsnapshot *tbs)
560{
561 _rawstring_init(&tbs->tbs_funcname);
562 _rawstring_init(&tbs->tbs_filename);
563 tbs->tbs_lineno = -1;
564 tbs->tbs_next = NULL;
565}
566
567static _tbsnapshot *
568_tbsnapshot_new(void)
569{
570 _tbsnapshot *tbs = PyMem_NEW(_tbsnapshot, 1);
571 if (tbs == NULL) {
572 PyErr_NoMemory();
573 return NULL;
574 }
575 _tbsnapshot_init(tbs);
576 return tbs;
577}
578
579static void _tbsnapshot_free(_tbsnapshot *); // forward
580
581static void
582_tbsnapshot_clear(_tbsnapshot *tbs)
583{
584 _rawstring_clear(&tbs->tbs_funcname);
585 _rawstring_clear(&tbs->tbs_filename);
586 tbs->tbs_lineno = -1;
587 if (tbs->tbs_next != NULL) {
588 _tbsnapshot_free(tbs->tbs_next);
589 tbs->tbs_next = NULL;
590 }
591}
592
593static void
594_tbsnapshot_free(_tbsnapshot *tbs)
595{
596 _tbsnapshot_clear(tbs);
597 PyMem_Free(tbs);
598}
599
600static int
601_tbsnapshot_is_clear(_tbsnapshot *tbs)
602{
603 return tbs->tbs_lineno == -1 && tbs->tbs_next == NULL
604 && _rawstring_is_clear(&tbs->tbs_funcname)
605 && _rawstring_is_clear(&tbs->tbs_filename);
606}
607
608static int
609_tbsnapshot_from_pytb(_tbsnapshot *tbs, PyTracebackObject *pytb)
610{
611 assert(_tbsnapshot_is_clear(tbs));
612 assert(pytb != NULL);
613
614 PyCodeObject *pycode = pytb->tb_frame->f_code;
615 const char *funcname = PyUnicode_AsUTF8(pycode->co_name);
616 if (_rawstring_strcpy(&tbs->tbs_funcname, funcname, 0) != 0) {
617 goto error;
618 }
619 const char *filename = PyUnicode_AsUTF8(pycode->co_filename);
620 if (_rawstring_strcpy(&tbs->tbs_filename, filename, 0) != 0) {
621 goto error;
622 }
623 tbs->tbs_lineno = pytb->tb_lineno;
624
625 return 0;
626
627error:
628 _tbsnapshot_clear(tbs);
629 return -1;
630}
631
632static int
633_tbsnapshot_extract(_tbsnapshot *tbs, PyTracebackObject *pytb)
634{
635 assert(_tbsnapshot_is_clear(tbs));
636 assert(pytb != NULL);
637
638 _tbsnapshot *next = NULL;
639 while (pytb->tb_next != NULL) {
640 _tbsnapshot *_next = _tbsnapshot_new();
641 if (_next == NULL) {
642 goto error;
643 }
644 if (_tbsnapshot_from_pytb(_next, pytb) != 0) {
645 goto error;
646 }
647 if (next != NULL) {
648 _next->tbs_next = next;
649 }
650 next = _next;
651 pytb = pytb->tb_next;
652 }
653 if (_tbsnapshot_from_pytb(tbs, pytb) != 0) {
654 goto error;
655 }
656 tbs->tbs_next = next;
657
658 return 0;
659
660error:
661 _tbsnapshot_clear(tbs);
662 return -1;
663}
664
665static PyObject *
666_tbsnapshot_resolve(_tbsnapshot *tbs)
667{
668 assert(!PyErr_Occurred());
669 // At this point there should be no traceback set yet.
670
671 while (tbs != NULL) {
672 const char *funcname = tbs->tbs_funcname.data;
673 const char *filename = tbs->tbs_filename.data;
674 _PyTraceback_Add(funcname ? funcname : "",
675 filename ? filename : "",
676 tbs->tbs_lineno);
677 tbs = tbs->tbs_next;
678 }
679
680 PyObject *exctype = NULL, *excval = NULL, *tb = NULL;
681 PyErr_Fetch(&exctype, &excval, &tb);
682 // Leave it cleared.
683 return tb;
684}
685
686/* exception snapshots */
687
688typedef struct _excsnapshot {
689 _objsnapshot es_object;
690 _rawstring *es_msg;
691 struct _excsnapshot *es_cause;
692 struct _excsnapshot *es_context;
693 char es_suppress_context;
694 struct _tbsnapshot *es_traceback;
695} _excsnapshot;
696
697static void
698_excsnapshot_init(_excsnapshot *es)
699{
700 _objsnapshot_init(&es->es_object);
701 es->es_msg = NULL;
702 es->es_cause = NULL;
703 es->es_context = NULL;
704 es->es_suppress_context = 0;
705 es->es_traceback = NULL;
706}
707
708static _excsnapshot *
709_excsnapshot_new(void) {
710 _excsnapshot *es = PyMem_NEW(_excsnapshot, 1);
711 if (es == NULL) {
712 PyErr_NoMemory();
713 return NULL;
714 }
715 _excsnapshot_init(es);
716 return es;
717}
718
719static void _excsnapshot_free(_excsnapshot *); // forward
720
721static void
722_excsnapshot_clear(_excsnapshot *es)
723{
724 _objsnapshot_clear(&es->es_object);
725 if (es->es_msg != NULL) {
726 _rawstring_free(es->es_msg);
727 es->es_msg = NULL;
728 }
729 if (es->es_cause != NULL) {
730 _excsnapshot_free(es->es_cause);
731 es->es_cause = NULL;
732 }
733 if (es->es_context != NULL) {
734 _excsnapshot_free(es->es_context);
735 es->es_context = NULL;
736 }
737 es->es_suppress_context = 0;
738 if (es->es_traceback != NULL) {
739 _tbsnapshot_free(es->es_traceback);
740 es->es_traceback = NULL;
741 }
742}
743
744static void
745_excsnapshot_free(_excsnapshot *es)
746{
747 _excsnapshot_clear(es);
748 PyMem_Free(es);
749}
750
751static int
752_excsnapshot_is_clear(_excsnapshot *es)
753{
754 return es->es_suppress_context == 0
755 && es->es_cause == NULL
756 && es->es_context == NULL
757 && es->es_traceback == NULL
758 && es->es_msg == NULL
759 && _objsnapshot_is_clear(&es->es_object);
760}
761
762static PyObject *
763_excsnapshot_get_exc_naive(_excsnapshot *es)
764{
765 _rawstring buf;
766 const char *msg = NULL;
767 if (es->es_msg != NULL) {
768 msg = es->es_msg->data;
769 } else {
770 _objsnapshot_summarize(&es->es_object, &buf, NULL);
771 if (buf.size > 0) {
772 msg = buf.data;
773 }
774 }
775
776 PyObject *exc = NULL;
777 // XXX Use _objsnapshot_resolve_naive()?
778 const char *modname = es->es_object.modname.size > 0
779 ? es->es_object.modname.data
780 : NULL;
781 PyObject *exctype = _pyobj_get_class(modname, es->es_object.clsname.data);
782 if (exctype != NULL) {
783 exc = _pyexc_create(exctype, msg, NULL);
784 Py_DECREF(exctype);
785 if (exc != NULL) {
786 return exc;
787 }
788 PyErr_Clear();
789 } else {
790 PyErr_Clear();
791 }
792 exctype = PyExc_Exception;
793 return _pyexc_create(exctype, msg, NULL);
794}
795
796static PyObject *
797_excsnapshot_get_exc(_excsnapshot *es)
798{
799 assert(!_objsnapshot_is_clear(&es->es_object));
800
801 PyObject *exc = _objsnapshot_resolve(&es->es_object);
802 if (exc == NULL) {
803 // Fall back to resolving the object.
804 PyObject *curtype = NULL, *curexc = NULL, *curtb = NULL;
805 PyErr_Fetch(&curtype, &curexc, &curtb);
806
807 exc = _excsnapshot_get_exc_naive(es);
808 if (exc == NULL) {
809 PyErr_Restore(curtype, curexc, curtb);
810 return NULL;
811 }
812 }
813 // People can do some weird stuff...
814 if (!PyExceptionInstance_Check(exc)) {
815 // We got a bogus "exception".
816 Py_DECREF(exc);
817 PyErr_SetString(PyExc_TypeError, "expected exception");
818 return NULL;
819 }
820 return exc;
821}
822
823static void _excsnapshot_extract(_excsnapshot *, PyObject *);
824static void
825_excsnapshot_extract(_excsnapshot *es, PyObject *excobj)
826{
827 assert(_excsnapshot_is_clear(es));
828 assert(PyExceptionInstance_Check(excobj));
829
830 _objsnapshot_extract(&es->es_object, excobj);
831
832 es->es_msg = _objsnapshot_get_minimal_summary(&es->es_object, excobj);
833 if (es->es_msg == NULL) {
834 PyErr_Clear();
835 }
836
837 PyBaseExceptionObject *exc = (PyBaseExceptionObject *)excobj;
838
839 if (exc->cause != NULL && exc->cause != Py_None) {
840 es->es_cause = _excsnapshot_new();
841 _excsnapshot_extract(es->es_cause, exc->cause);
842 }
843
844 if (exc->context != NULL && exc->context != Py_None) {
845 es->es_context = _excsnapshot_new();
846 _excsnapshot_extract(es->es_context, exc->context);
847 }
848
849 es->es_suppress_context = exc->suppress_context;
850
851 PyObject *tb = PyException_GetTraceback(excobj);
852 if (PyErr_Occurred()) {
853 IGNORE_FAILURE("could not get traceback");
854 } else if (tb == Py_None) {
855 Py_DECREF(tb);
856 tb = NULL;
857 }
858 if (tb != NULL) {
859 es->es_traceback = _tbsnapshot_new();
860 if (_tbsnapshot_extract(es->es_traceback,
861 (PyTracebackObject *)tb) != 0) {
862 IGNORE_FAILURE("could not extract __traceback__");
863 }
864 }
865}
866
867static PyObject *
868_excsnapshot_resolve(_excsnapshot *es)
869{
870 PyObject *exc = _excsnapshot_get_exc(es);
871 if (exc == NULL) {
872 return NULL;
873 }
874
875 if (es->es_traceback != NULL) {
876 PyObject *tb = _tbsnapshot_resolve(es->es_traceback);
877 if (tb == NULL) {
878 // The snapshot is still somewhat useful without this.
879 IGNORE_FAILURE("could not deserialize traceback");
880 } else {
881 // This does not steal references.
882 PyException_SetTraceback(exc, tb);
883 Py_DECREF(tb);
884 }
885 }
886 // NULL means "not set".
887
888 if (es->es_context != NULL) {
889 PyObject *context = _excsnapshot_resolve(es->es_context);
890 if (context == NULL) {
891 // The snapshot is still useful without this.
892 IGNORE_FAILURE("could not deserialize __context__");
893 } else {
894 // This steals references but we have one to give.
895 PyException_SetContext(exc, context);
896 }
897 }
898 // NULL means "not set".
899
900 if (es->es_cause != NULL) {
901 PyObject *cause = _excsnapshot_resolve(es->es_cause);
902 if (cause == NULL) {
903 // The snapshot is still useful without this.
904 IGNORE_FAILURE("could not deserialize __cause__");
905 } else {
906 // This steals references, but we have one to give.
907 PyException_SetCause(exc, cause);
908 }
909 }
910 // NULL means "not set".
911
912 ((PyBaseExceptionObject *)exc)->suppress_context = es->es_suppress_context;
913
914 return exc;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700915}
916
Eric Snow4e9da0d2018-02-02 21:49:49 -0700917
Eric Snow7f8bfc92018-01-29 18:23:44 -0700918/* data-sharing-specific code ***********************************************/
919
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600920/* shared "object" */
921
Eric Snow4e9da0d2018-02-02 21:49:49 -0700922struct _sharednsitem {
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600923 _rawstring name;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700924 _PyCrossInterpreterData data;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700925};
Eric Snow7f8bfc92018-01-29 18:23:44 -0700926
Eric Snowc11183c2019-03-15 16:35:46 -0600927static void _sharednsitem_clear(struct _sharednsitem *); // forward
928
Eric Snow4e9da0d2018-02-02 21:49:49 -0700929static int
930_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700931{
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600932 if (_rawstring_from_pyobj(&item->name, key) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700933 return -1;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700934 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700935 if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
Eric Snowc11183c2019-03-15 16:35:46 -0600936 _sharednsitem_clear(item);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700937 return -1;
938 }
939 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700940}
941
Eric Snow4e9da0d2018-02-02 21:49:49 -0700942static void
943_sharednsitem_clear(struct _sharednsitem *item)
944{
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600945 _rawstring_clear(&item->name);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700946 _PyCrossInterpreterData_Release(&item->data);
947}
948
949static int
950_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
951{
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600952 PyObject *name = PyUnicode_FromString(item->name.data);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700953 if (name == NULL) {
954 return -1;
955 }
956 PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
957 if (value == NULL) {
958 Py_DECREF(name);
959 return -1;
960 }
961 int res = PyDict_SetItem(ns, name, value);
962 Py_DECREF(name);
963 Py_DECREF(value);
964 return res;
965}
966
967typedef struct _sharedns {
968 Py_ssize_t len;
969 struct _sharednsitem* items;
970} _sharedns;
971
972static _sharedns *
973_sharedns_new(Py_ssize_t len)
974{
975 _sharedns *shared = PyMem_NEW(_sharedns, 1);
976 if (shared == NULL) {
977 PyErr_NoMemory();
978 return NULL;
979 }
980 shared->len = len;
981 shared->items = PyMem_NEW(struct _sharednsitem, len);
982 if (shared->items == NULL) {
983 PyErr_NoMemory();
984 PyMem_Free(shared);
985 return NULL;
986 }
987 return shared;
988}
989
990static void
991_sharedns_free(_sharedns *shared)
992{
993 for (Py_ssize_t i=0; i < shared->len; i++) {
994 _sharednsitem_clear(&shared->items[i]);
995 }
996 PyMem_Free(shared->items);
997 PyMem_Free(shared);
998}
999
1000static _sharedns *
1001_get_shared_ns(PyObject *shareable)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001002{
1003 if (shareable == NULL || shareable == Py_None) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001004 return NULL;
1005 }
1006 Py_ssize_t len = PyDict_Size(shareable);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001007 if (len == 0) {
1008 return NULL;
1009 }
1010
Eric Snow4e9da0d2018-02-02 21:49:49 -07001011 _sharedns *shared = _sharedns_new(len);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001012 if (shared == NULL) {
1013 return NULL;
1014 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001015 Py_ssize_t pos = 0;
1016 for (Py_ssize_t i=0; i < len; i++) {
1017 PyObject *key, *value;
1018 if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
1019 break;
1020 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001021 if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001022 break;
1023 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001024 }
1025 if (PyErr_Occurred()) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001026 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001027 return NULL;
1028 }
1029 return shared;
1030}
1031
1032static int
Eric Snow4e9da0d2018-02-02 21:49:49 -07001033_sharedns_apply(_sharedns *shared, PyObject *ns)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001034{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001035 for (Py_ssize_t i=0; i < shared->len; i++) {
1036 if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
1037 return -1;
1038 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001039 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001040 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001041}
1042
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001043/* shared exception */
1044
Eric Snow7f8bfc92018-01-29 18:23:44 -07001045// Ultimately we'd like to preserve enough information about the
1046// exception and traceback that we could re-constitute (or at least
1047// simulate, a la traceback.TracebackException), and even chain, a copy
1048// of the exception in the calling interpreter.
1049
1050typedef struct _sharedexception {
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001051 _excsnapshot snapshot;
1052 _rawstring msg;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001053} _sharedexception;
1054
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001055static void
1056_sharedexception_init(_sharedexception *she)
1057{
1058 _excsnapshot_init(&she->snapshot);
1059 _rawstring_init(&she->msg);
1060}
1061
Eric Snow7f8bfc92018-01-29 18:23:44 -07001062static _sharedexception *
Eric Snow4e9da0d2018-02-02 21:49:49 -07001063_sharedexception_new(void)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001064{
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001065 _sharedexception *she = PyMem_NEW(_sharedexception, 1);
1066 if (she == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001067 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -07001068 return NULL;
1069 }
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001070 _sharedexception_init(she);
1071 return she;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001072}
1073
1074static void
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001075_sharedexception_clear(_sharedexception *she)
Eric Snow4e9da0d2018-02-02 21:49:49 -07001076{
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001077 _excsnapshot_clear(&she->snapshot);
1078 _rawstring_clear(&she->msg);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001079}
1080
1081static void
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001082_sharedexception_free(_sharedexception *she)
Eric Snow4e9da0d2018-02-02 21:49:49 -07001083{
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001084 _sharedexception_clear(she);
1085 PyMem_Free(she);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001086}
1087
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001088static int
1089_sharedexception_is_clear(_sharedexception *she)
Eric Snow4e9da0d2018-02-02 21:49:49 -07001090{
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001091 return 1
1092 && _excsnapshot_is_clear(&she->snapshot)
1093 && _rawstring_is_clear(&she->msg);
1094}
Eric Snow4e9da0d2018-02-02 21:49:49 -07001095
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001096static PyObject *
1097_sharedexception_get_cause(_sharedexception *sharedexc)
1098{
1099 // FYI, "cause" is already normalized.
1100 PyObject *cause = _excsnapshot_resolve(&sharedexc->snapshot);
1101 if (cause == NULL) {
1102 if (PyErr_Occurred()) {
1103 IGNORE_FAILURE("could not deserialize exc snapshot");
Eric Snow4e9da0d2018-02-02 21:49:49 -07001104 }
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001105 return NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001106 }
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001107 // XXX Ensure "cause" has a traceback.
1108 return cause;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001109}
1110
Eric Snow7f8bfc92018-01-29 18:23:44 -07001111static void
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001112_sharedexception_extract(_sharedexception *she, PyObject *exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001113{
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001114 assert(_sharedexception_is_clear(she));
1115 assert(exc != NULL);
1116
1117 _excsnapshot_extract(&she->snapshot, exc);
1118
1119 // Compose the message.
1120 const char *msg = NULL;
1121 PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
1122 if (msgobj == NULL) {
1123 IGNORE_FAILURE("unable to format exception message");
1124 } else {
1125 msg = PyUnicode_AsUTF8(msgobj);
1126 if (PyErr_Occurred()) {
1127 PyErr_Clear();
Eric Snow4e9da0d2018-02-02 21:49:49 -07001128 }
1129 }
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001130 _objsnapshot_summarize(&she->snapshot.es_object, &she->msg, msg);
1131 Py_XDECREF(msgobj);
1132}
1133
1134static PyObject *
1135_sharedexception_resolve(_sharedexception *sharedexc, PyObject *wrapperclass)
1136{
1137 assert(!PyErr_Occurred());
1138
1139 // Get the exception object (already normalized).
1140 PyObject *exc = _pyexc_create(wrapperclass, sharedexc->msg.data, NULL);
1141 assert(exc != NULL);
1142
1143 // Set __cause__, is possible.
1144 PyObject *cause = _sharedexception_get_cause(sharedexc);
1145 if (cause != NULL) {
1146 // Set __context__.
1147 Py_INCREF(cause); // PyException_SetContext() steals a reference.
1148 PyException_SetContext(exc, cause);
1149
1150 // Set __cause__.
1151 Py_INCREF(cause); // PyException_SetCause() steals a reference.
1152 PyException_SetCause(exc, cause);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001153 }
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001154
1155 return exc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001156}
1157
Eric Snow4e9da0d2018-02-02 21:49:49 -07001158
1159/* channel-specific code ****************************************************/
Eric Snow7f8bfc92018-01-29 18:23:44 -07001160
Eric Snow3ab01362018-05-17 10:27:09 -04001161#define CHANNEL_SEND 1
1162#define CHANNEL_BOTH 0
1163#define CHANNEL_RECV -1
1164
Eric Snow7f8bfc92018-01-29 18:23:44 -07001165static PyObject *ChannelError;
1166static PyObject *ChannelNotFoundError;
1167static PyObject *ChannelClosedError;
1168static PyObject *ChannelEmptyError;
Eric Snow3ab01362018-05-17 10:27:09 -04001169static PyObject *ChannelNotEmptyError;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001170
1171static int
1172channel_exceptions_init(PyObject *ns)
1173{
1174 // XXX Move the exceptions into per-module memory?
1175
1176 // A channel-related operation failed.
1177 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
1178 PyExc_RuntimeError, NULL);
1179 if (ChannelError == NULL) {
1180 return -1;
1181 }
1182 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
1183 return -1;
1184 }
1185
1186 // An operation tried to use a channel that doesn't exist.
1187 ChannelNotFoundError = PyErr_NewException(
1188 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
1189 if (ChannelNotFoundError == NULL) {
1190 return -1;
1191 }
1192 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
1193 return -1;
1194 }
1195
1196 // An operation tried to use a closed channel.
1197 ChannelClosedError = PyErr_NewException(
1198 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
1199 if (ChannelClosedError == NULL) {
1200 return -1;
1201 }
1202 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
1203 return -1;
1204 }
1205
1206 // An operation tried to pop from an empty channel.
1207 ChannelEmptyError = PyErr_NewException(
1208 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
1209 if (ChannelEmptyError == NULL) {
1210 return -1;
1211 }
1212 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
1213 return -1;
1214 }
1215
Eric Snow3ab01362018-05-17 10:27:09 -04001216 // An operation tried to close a non-empty channel.
1217 ChannelNotEmptyError = PyErr_NewException(
1218 "_xxsubinterpreters.ChannelNotEmptyError", ChannelError, NULL);
1219 if (ChannelNotEmptyError == NULL) {
1220 return -1;
1221 }
1222 if (PyDict_SetItemString(ns, "ChannelNotEmptyError", ChannelNotEmptyError) != 0) {
1223 return -1;
1224 }
1225
Eric Snow7f8bfc92018-01-29 18:23:44 -07001226 return 0;
1227}
1228
Eric Snow4e9da0d2018-02-02 21:49:49 -07001229/* the channel queue */
1230
1231struct _channelitem;
1232
1233typedef struct _channelitem {
1234 _PyCrossInterpreterData *data;
1235 struct _channelitem *next;
1236} _channelitem;
1237
1238static _channelitem *
1239_channelitem_new(void)
1240{
1241 _channelitem *item = PyMem_NEW(_channelitem, 1);
1242 if (item == NULL) {
1243 PyErr_NoMemory();
1244 return NULL;
1245 }
1246 item->data = NULL;
1247 item->next = NULL;
1248 return item;
1249}
1250
1251static void
1252_channelitem_clear(_channelitem *item)
1253{
1254 if (item->data != NULL) {
1255 _PyCrossInterpreterData_Release(item->data);
1256 PyMem_Free(item->data);
1257 item->data = NULL;
1258 }
1259 item->next = NULL;
1260}
1261
1262static void
1263_channelitem_free(_channelitem *item)
1264{
1265 _channelitem_clear(item);
1266 PyMem_Free(item);
1267}
1268
1269static void
1270_channelitem_free_all(_channelitem *item)
1271{
1272 while (item != NULL) {
1273 _channelitem *last = item;
1274 item = item->next;
1275 _channelitem_free(last);
1276 }
1277}
1278
1279static _PyCrossInterpreterData *
1280_channelitem_popped(_channelitem *item)
1281{
1282 _PyCrossInterpreterData *data = item->data;
1283 item->data = NULL;
1284 _channelitem_free(item);
1285 return data;
1286}
1287
1288typedef struct _channelqueue {
1289 int64_t count;
1290 _channelitem *first;
1291 _channelitem *last;
1292} _channelqueue;
1293
1294static _channelqueue *
1295_channelqueue_new(void)
1296{
1297 _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
1298 if (queue == NULL) {
1299 PyErr_NoMemory();
1300 return NULL;
1301 }
1302 queue->count = 0;
1303 queue->first = NULL;
1304 queue->last = NULL;
1305 return queue;
1306}
1307
1308static void
1309_channelqueue_clear(_channelqueue *queue)
1310{
1311 _channelitem_free_all(queue->first);
1312 queue->count = 0;
1313 queue->first = NULL;
1314 queue->last = NULL;
1315}
1316
1317static void
1318_channelqueue_free(_channelqueue *queue)
1319{
1320 _channelqueue_clear(queue);
1321 PyMem_Free(queue);
1322}
1323
1324static int
1325_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
1326{
1327 _channelitem *item = _channelitem_new();
1328 if (item == NULL) {
1329 return -1;
1330 }
1331 item->data = data;
1332
1333 queue->count += 1;
1334 if (queue->first == NULL) {
1335 queue->first = item;
1336 }
1337 else {
1338 queue->last->next = item;
1339 }
1340 queue->last = item;
1341 return 0;
1342}
1343
1344static _PyCrossInterpreterData *
1345_channelqueue_get(_channelqueue *queue)
1346{
1347 _channelitem *item = queue->first;
1348 if (item == NULL) {
1349 return NULL;
1350 }
1351 queue->first = item->next;
1352 if (queue->last == item) {
1353 queue->last = NULL;
1354 }
1355 queue->count -= 1;
1356
1357 return _channelitem_popped(item);
1358}
1359
1360/* channel-interpreter associations */
1361
Eric Snow7f8bfc92018-01-29 18:23:44 -07001362struct _channelend;
1363
1364typedef struct _channelend {
1365 struct _channelend *next;
1366 int64_t interp;
1367 int open;
1368} _channelend;
1369
1370static _channelend *
1371_channelend_new(int64_t interp)
1372{
1373 _channelend *end = PyMem_NEW(_channelend, 1);
1374 if (end == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001375 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -07001376 return NULL;
1377 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001378 end->next = NULL;
1379 end->interp = interp;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001380 end->open = 1;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001381 return end;
1382}
1383
1384static void
Eric Snow4e9da0d2018-02-02 21:49:49 -07001385_channelend_free(_channelend *end)
1386{
1387 PyMem_Free(end);
1388}
1389
1390static void
1391_channelend_free_all(_channelend *end)
1392{
Eric Snow7f8bfc92018-01-29 18:23:44 -07001393 while (end != NULL) {
1394 _channelend *last = end;
1395 end = end->next;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001396 _channelend_free(last);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001397 }
1398}
1399
1400static _channelend *
1401_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
1402{
1403 _channelend *prev = NULL;
1404 _channelend *end = first;
1405 while (end != NULL) {
1406 if (end->interp == interp) {
1407 break;
1408 }
1409 prev = end;
1410 end = end->next;
1411 }
1412 if (pprev != NULL) {
1413 *pprev = prev;
1414 }
1415 return end;
1416}
1417
Eric Snow4e9da0d2018-02-02 21:49:49 -07001418typedef struct _channelassociations {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001419 // Note that the list entries are never removed for interpreter
Lewis Gaulf7bbf582020-04-29 01:18:42 +01001420 // for which the channel is closed. This should not be a problem in
Eric Snow7f8bfc92018-01-29 18:23:44 -07001421 // practice. Also, a channel isn't automatically closed when an
1422 // interpreter is destroyed.
1423 int64_t numsendopen;
1424 int64_t numrecvopen;
1425 _channelend *send;
1426 _channelend *recv;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001427} _channelends;
1428
1429static _channelends *
1430_channelends_new(void)
1431{
1432 _channelends *ends = PyMem_NEW(_channelends, 1);
1433 if (ends== NULL) {
1434 return NULL;
1435 }
1436 ends->numsendopen = 0;
1437 ends->numrecvopen = 0;
1438 ends->send = NULL;
1439 ends->recv = NULL;
1440 return ends;
1441}
1442
1443static void
1444_channelends_clear(_channelends *ends)
1445{
1446 _channelend_free_all(ends->send);
1447 ends->send = NULL;
1448 ends->numsendopen = 0;
1449
1450 _channelend_free_all(ends->recv);
1451 ends->recv = NULL;
1452 ends->numrecvopen = 0;
1453}
1454
1455static void
1456_channelends_free(_channelends *ends)
1457{
1458 _channelends_clear(ends);
1459 PyMem_Free(ends);
1460}
1461
1462static _channelend *
1463_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
1464 int send)
1465{
1466 _channelend *end = _channelend_new(interp);
1467 if (end == NULL) {
1468 return NULL;
1469 }
1470
1471 if (prev == NULL) {
1472 if (send) {
1473 ends->send = end;
1474 }
1475 else {
1476 ends->recv = end;
1477 }
1478 }
1479 else {
1480 prev->next = end;
1481 }
1482 if (send) {
1483 ends->numsendopen += 1;
1484 }
1485 else {
1486 ends->numrecvopen += 1;
1487 }
1488 return end;
1489}
1490
1491static int
1492_channelends_associate(_channelends *ends, int64_t interp, int send)
1493{
1494 _channelend *prev;
1495 _channelend *end = _channelend_find(send ? ends->send : ends->recv,
1496 interp, &prev);
1497 if (end != NULL) {
1498 if (!end->open) {
1499 PyErr_SetString(ChannelClosedError, "channel already closed");
1500 return -1;
1501 }
1502 // already associated
1503 return 0;
1504 }
1505 if (_channelends_add(ends, prev, interp, send) == NULL) {
1506 return -1;
1507 }
1508 return 0;
1509}
1510
1511static int
1512_channelends_is_open(_channelends *ends)
1513{
1514 if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
1515 return 1;
1516 }
1517 if (ends->send == NULL && ends->recv == NULL) {
1518 return 1;
1519 }
1520 return 0;
1521}
1522
1523static void
1524_channelends_close_end(_channelends *ends, _channelend *end, int send)
1525{
1526 end->open = 0;
1527 if (send) {
1528 ends->numsendopen -= 1;
1529 }
1530 else {
1531 ends->numrecvopen -= 1;
1532 }
1533}
1534
1535static int
1536_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
1537{
1538 _channelend *prev;
1539 _channelend *end;
1540 if (which >= 0) { // send/both
1541 end = _channelend_find(ends->send, interp, &prev);
1542 if (end == NULL) {
1543 // never associated so add it
1544 end = _channelends_add(ends, prev, interp, 1);
1545 if (end == NULL) {
1546 return -1;
1547 }
1548 }
1549 _channelends_close_end(ends, end, 1);
1550 }
1551 if (which <= 0) { // recv/both
1552 end = _channelend_find(ends->recv, interp, &prev);
1553 if (end == NULL) {
1554 // never associated so add it
1555 end = _channelends_add(ends, prev, interp, 0);
1556 if (end == NULL) {
1557 return -1;
1558 }
1559 }
1560 _channelends_close_end(ends, end, 0);
1561 }
1562 return 0;
1563}
1564
1565static void
Eric Snow3ab01362018-05-17 10:27:09 -04001566_channelends_close_all(_channelends *ends, int which, int force)
Eric Snow4e9da0d2018-02-02 21:49:49 -07001567{
Eric Snow3ab01362018-05-17 10:27:09 -04001568 // XXX Handle the ends.
1569 // XXX Handle force is True.
1570
Eric Snow4e9da0d2018-02-02 21:49:49 -07001571 // Ensure all the "send"-associated interpreters are closed.
1572 _channelend *end;
1573 for (end = ends->send; end != NULL; end = end->next) {
1574 _channelends_close_end(ends, end, 1);
1575 }
1576
1577 // Ensure all the "recv"-associated interpreters are closed.
1578 for (end = ends->recv; end != NULL; end = end->next) {
1579 _channelends_close_end(ends, end, 0);
1580 }
1581}
1582
1583/* channels */
1584
1585struct _channel;
Eric Snow3ab01362018-05-17 10:27:09 -04001586struct _channel_closing;
1587static void _channel_clear_closing(struct _channel *);
1588static void _channel_finish_closing(struct _channel *);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001589
1590typedef struct _channel {
1591 PyThread_type_lock mutex;
1592 _channelqueue *queue;
1593 _channelends *ends;
1594 int open;
Eric Snow3ab01362018-05-17 10:27:09 -04001595 struct _channel_closing *closing;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001596} _PyChannelState;
1597
1598static _PyChannelState *
1599_channel_new(void)
1600{
1601 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
1602 if (chan == NULL) {
1603 return NULL;
1604 }
1605 chan->mutex = PyThread_allocate_lock();
1606 if (chan->mutex == NULL) {
1607 PyMem_Free(chan);
1608 PyErr_SetString(ChannelError,
1609 "can't initialize mutex for new channel");
1610 return NULL;
1611 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001612 chan->queue = _channelqueue_new();
1613 if (chan->queue == NULL) {
1614 PyMem_Free(chan);
1615 return NULL;
1616 }
1617 chan->ends = _channelends_new();
1618 if (chan->ends == NULL) {
1619 _channelqueue_free(chan->queue);
1620 PyMem_Free(chan);
1621 return NULL;
1622 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001623 chan->open = 1;
Eric Snow3ab01362018-05-17 10:27:09 -04001624 chan->closing = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001625 return chan;
1626}
1627
Eric Snow4e9da0d2018-02-02 21:49:49 -07001628static void
1629_channel_free(_PyChannelState *chan)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001630{
Eric Snow3ab01362018-05-17 10:27:09 -04001631 _channel_clear_closing(chan);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001632 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1633 _channelqueue_free(chan->queue);
1634 _channelends_free(chan->ends);
1635 PyThread_release_lock(chan->mutex);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001636
Eric Snow4e9da0d2018-02-02 21:49:49 -07001637 PyThread_free_lock(chan->mutex);
1638 PyMem_Free(chan);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001639}
1640
Eric Snow4e9da0d2018-02-02 21:49:49 -07001641static int
1642_channel_add(_PyChannelState *chan, int64_t interp,
1643 _PyCrossInterpreterData *data)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001644{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001645 int res = -1;
1646 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1647
Eric Snow7f8bfc92018-01-29 18:23:44 -07001648 if (!chan->open) {
1649 PyErr_SetString(ChannelClosedError, "channel closed");
Eric Snow4e9da0d2018-02-02 21:49:49 -07001650 goto done;
1651 }
1652 if (_channelends_associate(chan->ends, interp, 1) != 0) {
1653 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001654 }
1655
Eric Snow4e9da0d2018-02-02 21:49:49 -07001656 if (_channelqueue_put(chan->queue, data) != 0) {
1657 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001658 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001659
1660 res = 0;
1661done:
1662 PyThread_release_lock(chan->mutex);
1663 return res;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001664}
1665
Eric Snow4e9da0d2018-02-02 21:49:49 -07001666static _PyCrossInterpreterData *
1667_channel_next(_PyChannelState *chan, int64_t interp)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001668{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001669 _PyCrossInterpreterData *data = NULL;
1670 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1671
1672 if (!chan->open) {
1673 PyErr_SetString(ChannelClosedError, "channel closed");
1674 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001675 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001676 if (_channelends_associate(chan->ends, interp, 0) != 0) {
1677 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001678 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001679
1680 data = _channelqueue_get(chan->queue);
Eric Snow3ab01362018-05-17 10:27:09 -04001681 if (data == NULL && !PyErr_Occurred() && chan->closing != NULL) {
1682 chan->open = 0;
1683 }
1684
Eric Snow4e9da0d2018-02-02 21:49:49 -07001685done:
1686 PyThread_release_lock(chan->mutex);
Eric Snow3ab01362018-05-17 10:27:09 -04001687 if (chan->queue->count == 0) {
1688 _channel_finish_closing(chan);
1689 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001690 return data;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001691}
1692
1693static int
Eric Snow3ab01362018-05-17 10:27:09 -04001694_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001695{
1696 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1697
1698 int res = -1;
1699 if (!chan->open) {
1700 PyErr_SetString(ChannelClosedError, "channel already closed");
1701 goto done;
1702 }
1703
Eric Snow3ab01362018-05-17 10:27:09 -04001704 if (_channelends_close_interpreter(chan->ends, interp, end) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001705 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001706 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001707 chan->open = _channelends_is_open(chan->ends);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001708
1709 res = 0;
1710done:
1711 PyThread_release_lock(chan->mutex);
1712 return res;
1713}
1714
1715static int
Eric Snow3ab01362018-05-17 10:27:09 -04001716_channel_close_all(_PyChannelState *chan, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001717{
1718 int res = -1;
1719 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1720
1721 if (!chan->open) {
1722 PyErr_SetString(ChannelClosedError, "channel already closed");
1723 goto done;
1724 }
1725
Eric Snow3ab01362018-05-17 10:27:09 -04001726 if (!force && chan->queue->count > 0) {
1727 PyErr_SetString(ChannelNotEmptyError,
1728 "may not be closed if not empty (try force=True)");
1729 goto done;
1730 }
1731
Eric Snow7f8bfc92018-01-29 18:23:44 -07001732 chan->open = 0;
1733
1734 // We *could* also just leave these in place, since we've marked
1735 // the channel as closed already.
Eric Snow3ab01362018-05-17 10:27:09 -04001736 _channelends_close_all(chan->ends, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001737
1738 res = 0;
1739done:
1740 PyThread_release_lock(chan->mutex);
1741 return res;
1742}
1743
Eric Snow4e9da0d2018-02-02 21:49:49 -07001744/* the set of channels */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001745
1746struct _channelref;
1747
1748typedef struct _channelref {
1749 int64_t id;
1750 _PyChannelState *chan;
1751 struct _channelref *next;
1752 Py_ssize_t objcount;
1753} _channelref;
1754
1755static _channelref *
1756_channelref_new(int64_t id, _PyChannelState *chan)
1757{
1758 _channelref *ref = PyMem_NEW(_channelref, 1);
1759 if (ref == NULL) {
1760 return NULL;
1761 }
1762 ref->id = id;
1763 ref->chan = chan;
1764 ref->next = NULL;
1765 ref->objcount = 0;
1766 return ref;
1767}
1768
Eric Snow4e9da0d2018-02-02 21:49:49 -07001769//static void
1770//_channelref_clear(_channelref *ref)
1771//{
1772// ref->id = -1;
1773// ref->chan = NULL;
1774// ref->next = NULL;
1775// ref->objcount = 0;
1776//}
1777
1778static void
1779_channelref_free(_channelref *ref)
1780{
Eric Snow3ab01362018-05-17 10:27:09 -04001781 if (ref->chan != NULL) {
1782 _channel_clear_closing(ref->chan);
1783 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001784 //_channelref_clear(ref);
1785 PyMem_Free(ref);
1786}
1787
Eric Snow7f8bfc92018-01-29 18:23:44 -07001788static _channelref *
1789_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
1790{
1791 _channelref *prev = NULL;
1792 _channelref *ref = first;
1793 while (ref != NULL) {
1794 if (ref->id == id) {
1795 break;
1796 }
1797 prev = ref;
1798 ref = ref->next;
1799 }
1800 if (pprev != NULL) {
1801 *pprev = prev;
1802 }
1803 return ref;
1804}
1805
1806typedef struct _channels {
1807 PyThread_type_lock mutex;
1808 _channelref *head;
1809 int64_t numopen;
1810 int64_t next_id;
1811} _channels;
1812
1813static int
1814_channels_init(_channels *channels)
1815{
1816 if (channels->mutex == NULL) {
1817 channels->mutex = PyThread_allocate_lock();
1818 if (channels->mutex == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001819 PyErr_SetString(ChannelError,
1820 "can't initialize mutex for channel management");
1821 return -1;
1822 }
1823 }
1824 channels->head = NULL;
1825 channels->numopen = 0;
1826 channels->next_id = 0;
1827 return 0;
1828}
1829
1830static int64_t
1831_channels_next_id(_channels *channels) // needs lock
1832{
1833 int64_t id = channels->next_id;
1834 if (id < 0) {
1835 /* overflow */
1836 PyErr_SetString(ChannelError,
1837 "failed to get a channel ID");
1838 return -1;
1839 }
1840 channels->next_id += 1;
1841 return id;
1842}
1843
1844static _PyChannelState *
1845_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
1846{
1847 _PyChannelState *chan = NULL;
1848 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1849 if (pmutex != NULL) {
1850 *pmutex = NULL;
1851 }
1852
1853 _channelref *ref = _channelref_find(channels->head, id, NULL);
1854 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001855 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001856 goto done;
1857 }
1858 if (ref->chan == NULL || !ref->chan->open) {
Eric Snowab4a1982018-06-13 08:02:39 -06001859 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001860 goto done;
1861 }
1862
1863 if (pmutex != NULL) {
1864 // The mutex will be closed by the caller.
1865 *pmutex = channels->mutex;
1866 }
1867
1868 chan = ref->chan;
1869done:
1870 if (pmutex == NULL || *pmutex == NULL) {
1871 PyThread_release_lock(channels->mutex);
1872 }
1873 return chan;
1874}
1875
1876static int64_t
1877_channels_add(_channels *channels, _PyChannelState *chan)
1878{
1879 int64_t cid = -1;
1880 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1881
1882 // Create a new ref.
1883 int64_t id = _channels_next_id(channels);
1884 if (id < 0) {
1885 goto done;
1886 }
1887 _channelref *ref = _channelref_new(id, chan);
1888 if (ref == NULL) {
1889 goto done;
1890 }
1891
1892 // Add it to the list.
1893 // We assume that the channel is a new one (not already in the list).
1894 ref->next = channels->head;
1895 channels->head = ref;
1896 channels->numopen += 1;
1897
1898 cid = id;
1899done:
1900 PyThread_release_lock(channels->mutex);
1901 return cid;
1902}
1903
Eric Snow3ab01362018-05-17 10:27:09 -04001904/* forward */
1905static int _channel_set_closing(struct _channelref *, PyThread_type_lock);
1906
Eric Snow7f8bfc92018-01-29 18:23:44 -07001907static int
Eric Snow3ab01362018-05-17 10:27:09 -04001908_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan,
1909 int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001910{
1911 int res = -1;
1912 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1913 if (pchan != NULL) {
1914 *pchan = NULL;
1915 }
1916
1917 _channelref *ref = _channelref_find(channels->head, cid, NULL);
1918 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001919 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001920 goto done;
1921 }
1922
1923 if (ref->chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001924 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001925 goto done;
1926 }
Eric Snow3ab01362018-05-17 10:27:09 -04001927 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001928 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001929 goto done;
1930 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001931 else {
Eric Snow3ab01362018-05-17 10:27:09 -04001932 if (_channel_close_all(ref->chan, end, force) != 0) {
1933 if (end == CHANNEL_SEND &&
1934 PyErr_ExceptionMatches(ChannelNotEmptyError)) {
1935 if (ref->chan->closing != NULL) {
Eric Snow6854e802018-06-01 16:26:01 -06001936 PyErr_Format(ChannelClosedError,
Eric Snowab4a1982018-06-13 08:02:39 -06001937 "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001938 goto done;
1939 }
1940 // Mark the channel as closing and return. The channel
1941 // will be cleaned up in _channel_next().
1942 PyErr_Clear();
1943 if (_channel_set_closing(ref, channels->mutex) != 0) {
1944 goto done;
1945 }
1946 if (pchan != NULL) {
1947 *pchan = ref->chan;
1948 }
1949 res = 0;
1950 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001951 goto done;
1952 }
1953 if (pchan != NULL) {
1954 *pchan = ref->chan;
1955 }
Eric Snow3ab01362018-05-17 10:27:09 -04001956 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001957 _channel_free(ref->chan);
1958 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001959 ref->chan = NULL;
1960 }
1961
1962 res = 0;
1963done:
1964 PyThread_release_lock(channels->mutex);
1965 return res;
1966}
1967
1968static void
1969_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1970 _PyChannelState **pchan)
1971{
1972 if (ref == channels->head) {
1973 channels->head = ref->next;
1974 }
1975 else {
1976 prev->next = ref->next;
1977 }
1978 channels->numopen -= 1;
1979
1980 if (pchan != NULL) {
1981 *pchan = ref->chan;
1982 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001983 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001984}
1985
1986static int
1987_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1988{
1989 int res = -1;
1990 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1991
1992 if (pchan != NULL) {
1993 *pchan = NULL;
1994 }
1995
1996 _channelref *prev = NULL;
1997 _channelref *ref = _channelref_find(channels->head, id, &prev);
1998 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001999 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002000 goto done;
2001 }
2002
2003 _channels_remove_ref(channels, ref, prev, pchan);
2004
2005 res = 0;
2006done:
2007 PyThread_release_lock(channels->mutex);
2008 return res;
2009}
2010
2011static int
2012_channels_add_id_object(_channels *channels, int64_t id)
2013{
2014 int res = -1;
2015 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
2016
2017 _channelref *ref = _channelref_find(channels->head, id, NULL);
2018 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06002019 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002020 goto done;
2021 }
2022 ref->objcount += 1;
2023
2024 res = 0;
2025done:
2026 PyThread_release_lock(channels->mutex);
2027 return res;
2028}
2029
2030static void
2031_channels_drop_id_object(_channels *channels, int64_t id)
2032{
2033 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
2034
2035 _channelref *prev = NULL;
2036 _channelref *ref = _channelref_find(channels->head, id, &prev);
2037 if (ref == NULL) {
2038 // Already destroyed.
2039 goto done;
2040 }
2041 ref->objcount -= 1;
2042
2043 // Destroy if no longer used.
2044 if (ref->objcount == 0) {
2045 _PyChannelState *chan = NULL;
2046 _channels_remove_ref(channels, ref, prev, &chan);
2047 if (chan != NULL) {
2048 _channel_free(chan);
2049 }
2050 }
2051
2052done:
2053 PyThread_release_lock(channels->mutex);
2054}
2055
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07002056static int64_t *
Eric Snow7f8bfc92018-01-29 18:23:44 -07002057_channels_list_all(_channels *channels, int64_t *count)
2058{
2059 int64_t *cids = NULL;
2060 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002061 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
2062 if (ids == NULL) {
2063 goto done;
2064 }
2065 _channelref *ref = channels->head;
2066 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
2067 ids[i] = ref->id;
2068 }
2069 *count = channels->numopen;
2070
2071 cids = ids;
2072done:
2073 PyThread_release_lock(channels->mutex);
2074 return cids;
2075}
2076
Eric Snow3ab01362018-05-17 10:27:09 -04002077/* support for closing non-empty channels */
2078
2079struct _channel_closing {
2080 struct _channelref *ref;
2081};
2082
2083static int
2084_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
2085 struct _channel *chan = ref->chan;
2086 if (chan == NULL) {
2087 // already closed
2088 return 0;
2089 }
2090 int res = -1;
2091 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
2092 if (chan->closing != NULL) {
2093 PyErr_SetString(ChannelClosedError, "channel closed");
2094 goto done;
2095 }
2096 chan->closing = PyMem_NEW(struct _channel_closing, 1);
2097 if (chan->closing == NULL) {
2098 goto done;
2099 }
2100 chan->closing->ref = ref;
2101
2102 res = 0;
2103done:
2104 PyThread_release_lock(chan->mutex);
2105 return res;
2106}
2107
2108static void
2109_channel_clear_closing(struct _channel *chan) {
2110 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
2111 if (chan->closing != NULL) {
2112 PyMem_Free(chan->closing);
2113 chan->closing = NULL;
2114 }
2115 PyThread_release_lock(chan->mutex);
2116}
2117
2118static void
2119_channel_finish_closing(struct _channel *chan) {
2120 struct _channel_closing *closing = chan->closing;
2121 if (closing == NULL) {
2122 return;
2123 }
2124 _channelref *ref = closing->ref;
2125 _channel_clear_closing(chan);
2126 // Do the things that would have been done in _channels_close().
2127 ref->chan = NULL;
2128 _channel_free(chan);
Zackery Spytz1a2252e2019-05-06 10:56:51 -06002129}
Eric Snow3ab01362018-05-17 10:27:09 -04002130
Eric Snow7f8bfc92018-01-29 18:23:44 -07002131/* "high"-level channel-related functions */
2132
2133static int64_t
2134_channel_create(_channels *channels)
2135{
2136 _PyChannelState *chan = _channel_new();
2137 if (chan == NULL) {
2138 return -1;
2139 }
2140 int64_t id = _channels_add(channels, chan);
2141 if (id < 0) {
2142 _channel_free(chan);
2143 return -1;
2144 }
2145 return id;
2146}
2147
2148static int
2149_channel_destroy(_channels *channels, int64_t id)
2150{
2151 _PyChannelState *chan = NULL;
2152 if (_channels_remove(channels, id, &chan) != 0) {
2153 return -1;
2154 }
2155 if (chan != NULL) {
2156 _channel_free(chan);
2157 }
2158 return 0;
2159}
2160
2161static int
2162_channel_send(_channels *channels, int64_t id, PyObject *obj)
2163{
2164 PyInterpreterState *interp = _get_current();
2165 if (interp == NULL) {
2166 return -1;
2167 }
2168
2169 // Look up the channel.
2170 PyThread_type_lock mutex = NULL;
2171 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
2172 if (chan == NULL) {
2173 return -1;
2174 }
2175 // Past this point we are responsible for releasing the mutex.
2176
Eric Snow3ab01362018-05-17 10:27:09 -04002177 if (chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06002178 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow3ab01362018-05-17 10:27:09 -04002179 PyThread_release_lock(mutex);
2180 return -1;
2181 }
2182
Eric Snow7f8bfc92018-01-29 18:23:44 -07002183 // Convert the object to cross-interpreter data.
2184 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
2185 if (data == NULL) {
2186 PyThread_release_lock(mutex);
2187 return -1;
2188 }
2189 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
Victor Stinner4d61e6e2019-03-04 14:21:28 +01002190 PyThread_release_lock(mutex);
Eric Snowc11183c2019-03-15 16:35:46 -06002191 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002192 return -1;
2193 }
2194
2195 // Add the data to the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06002196 int res = _channel_add(chan, PyInterpreterState_GetID(interp), data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002197 PyThread_release_lock(mutex);
2198 if (res != 0) {
2199 _PyCrossInterpreterData_Release(data);
2200 PyMem_Free(data);
2201 return -1;
2202 }
2203
2204 return 0;
2205}
2206
2207static PyObject *
2208_channel_recv(_channels *channels, int64_t id)
2209{
2210 PyInterpreterState *interp = _get_current();
2211 if (interp == NULL) {
2212 return NULL;
2213 }
2214
2215 // Look up the channel.
2216 PyThread_type_lock mutex = NULL;
2217 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
2218 if (chan == NULL) {
2219 return NULL;
2220 }
2221 // Past this point we are responsible for releasing the mutex.
2222
2223 // Pop off the next item from the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06002224 _PyCrossInterpreterData *data = _channel_next(chan, PyInterpreterState_GetID(interp));
Eric Snow7f8bfc92018-01-29 18:23:44 -07002225 PyThread_release_lock(mutex);
2226 if (data == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002227 return NULL;
2228 }
2229
2230 // Convert the data back to an object.
2231 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
Eric Snow5e8c6912020-04-28 17:11:32 -06002232 _PyCrossInterpreterData_Release(data);
2233 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002234 if (obj == NULL) {
2235 return NULL;
2236 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002237
2238 return obj;
2239}
2240
2241static int
2242_channel_drop(_channels *channels, int64_t id, int send, int recv)
2243{
2244 PyInterpreterState *interp = _get_current();
2245 if (interp == NULL) {
2246 return -1;
2247 }
2248
2249 // Look up the channel.
2250 PyThread_type_lock mutex = NULL;
2251 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
2252 if (chan == NULL) {
2253 return -1;
2254 }
2255 // Past this point we are responsible for releasing the mutex.
2256
2257 // Close one or both of the two ends.
Eric Snowc11183c2019-03-15 16:35:46 -06002258 int res = _channel_close_interpreter(chan, PyInterpreterState_GetID(interp), send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002259 PyThread_release_lock(mutex);
2260 return res;
2261}
2262
2263static int
Eric Snow3ab01362018-05-17 10:27:09 -04002264_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002265{
Eric Snow3ab01362018-05-17 10:27:09 -04002266 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002267}
2268
Lewis Gaulf7bbf582020-04-29 01:18:42 +01002269static int
2270_channel_is_associated(_channels *channels, int64_t cid, int64_t interp,
2271 int send)
2272{
2273 _PyChannelState *chan = _channels_lookup(channels, cid, NULL);
2274 if (chan == NULL) {
2275 return -1;
2276 } else if (send && chan->closing != NULL) {
2277 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
2278 return -1;
2279 }
2280
2281 _channelend *end = _channelend_find(send ? chan->ends->send : chan->ends->recv,
2282 interp, NULL);
2283
2284 return (end != NULL && end->open);
2285}
2286
Eric Snow7f8bfc92018-01-29 18:23:44 -07002287/* ChannelID class */
2288
Eric Snow7f8bfc92018-01-29 18:23:44 -07002289static PyTypeObject ChannelIDtype;
2290
2291typedef struct channelid {
2292 PyObject_HEAD
2293 int64_t id;
2294 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04002295 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002296 _channels *channels;
2297} channelid;
2298
Serhiy Storchakabf169912019-09-13 22:50:27 +03002299static int
2300channel_id_converter(PyObject *arg, void *ptr)
2301{
2302 int64_t cid;
2303 if (PyObject_TypeCheck(arg, &ChannelIDtype)) {
2304 cid = ((channelid *)arg)->id;
2305 }
2306 else if (PyIndex_Check(arg)) {
2307 cid = PyLong_AsLongLong(arg);
2308 if (cid == -1 && PyErr_Occurred()) {
2309 return 0;
2310 }
2311 if (cid < 0) {
2312 PyErr_Format(PyExc_ValueError,
2313 "channel ID must be a non-negative int, got %R", arg);
2314 return 0;
2315 }
2316 }
2317 else {
2318 PyErr_Format(PyExc_TypeError,
2319 "channel ID must be an int, got %.100s",
Victor Stinnerdaa97562020-02-07 03:37:06 +01002320 Py_TYPE(arg)->tp_name);
Serhiy Storchakabf169912019-09-13 22:50:27 +03002321 return 0;
2322 }
2323 *(int64_t *)ptr = cid;
2324 return 1;
2325}
2326
Eric Snow7f8bfc92018-01-29 18:23:44 -07002327static channelid *
2328newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04002329 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002330{
2331 channelid *self = PyObject_New(channelid, cls);
2332 if (self == NULL) {
2333 return NULL;
2334 }
2335 self->id = cid;
2336 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04002337 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002338 self->channels = channels;
2339
2340 if (_channels_add_id_object(channels, cid) != 0) {
2341 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
2342 PyErr_Clear();
2343 }
2344 else {
2345 Py_DECREF((PyObject *)self);
2346 return NULL;
2347 }
2348 }
2349
2350 return self;
2351}
2352
2353static _channels * _global_channels(void);
2354
2355static PyObject *
2356channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
2357{
Eric Snow6d2cd902018-05-16 15:04:57 -04002358 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002359 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002360 int send = -1;
2361 int recv = -1;
2362 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04002363 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002364 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03002365 "O&|$pppp:ChannelID.__new__", kwlist,
2366 channel_id_converter, &cid, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002367 return NULL;
2368
Eric Snow7f8bfc92018-01-29 18:23:44 -07002369 // Handle "send" and "recv".
2370 if (send == 0 && recv == 0) {
2371 PyErr_SetString(PyExc_ValueError,
2372 "'send' and 'recv' cannot both be False");
2373 return NULL;
2374 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002375
Eric Snow7f8bfc92018-01-29 18:23:44 -07002376 int end = 0;
2377 if (send == 1) {
2378 if (recv == 0 || recv == -1) {
2379 end = CHANNEL_SEND;
2380 }
2381 }
2382 else if (recv == 1) {
2383 end = CHANNEL_RECV;
2384 }
2385
Eric Snow6d2cd902018-05-16 15:04:57 -04002386 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
2387 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002388}
2389
2390static void
2391channelid_dealloc(PyObject *v)
2392{
2393 int64_t cid = ((channelid *)v)->id;
2394 _channels *channels = ((channelid *)v)->channels;
2395 Py_TYPE(v)->tp_free(v);
2396
2397 _channels_drop_id_object(channels, cid);
2398}
2399
2400static PyObject *
2401channelid_repr(PyObject *self)
2402{
2403 PyTypeObject *type = Py_TYPE(self);
2404 const char *name = _PyType_Name(type);
2405
2406 channelid *cid = (channelid *)self;
2407 const char *fmt;
2408 if (cid->end == CHANNEL_SEND) {
Eric Snowab4a1982018-06-13 08:02:39 -06002409 fmt = "%s(%" PRId64 ", send=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07002410 }
2411 else if (cid->end == CHANNEL_RECV) {
Eric Snowab4a1982018-06-13 08:02:39 -06002412 fmt = "%s(%" PRId64 ", recv=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07002413 }
2414 else {
Eric Snowab4a1982018-06-13 08:02:39 -06002415 fmt = "%s(%" PRId64 ")";
Eric Snow7f8bfc92018-01-29 18:23:44 -07002416 }
2417 return PyUnicode_FromFormat(fmt, name, cid->id);
2418}
2419
Eric Snow6d2cd902018-05-16 15:04:57 -04002420static PyObject *
2421channelid_str(PyObject *self)
2422{
2423 channelid *cid = (channelid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06002424 return PyUnicode_FromFormat("%" PRId64 "", cid->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04002425}
2426
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07002427static PyObject *
Eric Snow7f8bfc92018-01-29 18:23:44 -07002428channelid_int(PyObject *self)
2429{
2430 channelid *cid = (channelid *)self;
2431 return PyLong_FromLongLong(cid->id);
2432}
2433
2434static PyNumberMethods channelid_as_number = {
2435 0, /* nb_add */
2436 0, /* nb_subtract */
2437 0, /* nb_multiply */
2438 0, /* nb_remainder */
2439 0, /* nb_divmod */
2440 0, /* nb_power */
2441 0, /* nb_negative */
2442 0, /* nb_positive */
2443 0, /* nb_absolute */
2444 0, /* nb_bool */
2445 0, /* nb_invert */
2446 0, /* nb_lshift */
2447 0, /* nb_rshift */
2448 0, /* nb_and */
2449 0, /* nb_xor */
2450 0, /* nb_or */
2451 (unaryfunc)channelid_int, /* nb_int */
2452 0, /* nb_reserved */
2453 0, /* nb_float */
2454
2455 0, /* nb_inplace_add */
2456 0, /* nb_inplace_subtract */
2457 0, /* nb_inplace_multiply */
2458 0, /* nb_inplace_remainder */
2459 0, /* nb_inplace_power */
2460 0, /* nb_inplace_lshift */
2461 0, /* nb_inplace_rshift */
2462 0, /* nb_inplace_and */
2463 0, /* nb_inplace_xor */
2464 0, /* nb_inplace_or */
2465
2466 0, /* nb_floor_divide */
2467 0, /* nb_true_divide */
2468 0, /* nb_inplace_floor_divide */
2469 0, /* nb_inplace_true_divide */
2470
2471 (unaryfunc)channelid_int, /* nb_index */
2472};
2473
2474static Py_hash_t
2475channelid_hash(PyObject *self)
2476{
2477 channelid *cid = (channelid *)self;
2478 PyObject *id = PyLong_FromLongLong(cid->id);
2479 if (id == NULL) {
2480 return -1;
2481 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002482 Py_hash_t hash = PyObject_Hash(id);
2483 Py_DECREF(id);
2484 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002485}
2486
2487static PyObject *
2488channelid_richcompare(PyObject *self, PyObject *other, int op)
2489{
2490 if (op != Py_EQ && op != Py_NE) {
2491 Py_RETURN_NOTIMPLEMENTED;
2492 }
2493
2494 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
2495 Py_RETURN_NOTIMPLEMENTED;
2496 }
2497
2498 channelid *cid = (channelid *)self;
2499 int equal;
2500 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
2501 channelid *othercid = (channelid *)other;
Serhiy Storchakabf169912019-09-13 22:50:27 +03002502 equal = (cid->end == othercid->end) && (cid->id == othercid->id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002503 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03002504 else if (PyLong_Check(other)) {
2505 /* Fast path */
2506 int overflow;
2507 long long othercid = PyLong_AsLongLongAndOverflow(other, &overflow);
2508 if (othercid == -1 && PyErr_Occurred()) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002509 return NULL;
2510 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03002511 equal = !overflow && (othercid >= 0) && (cid->id == othercid);
2512 }
2513 else if (PyNumber_Check(other)) {
2514 PyObject *pyid = PyLong_FromLongLong(cid->id);
2515 if (pyid == NULL) {
2516 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002517 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03002518 PyObject *res = PyObject_RichCompare(pyid, other, op);
2519 Py_DECREF(pyid);
2520 return res;
2521 }
2522 else {
2523 Py_RETURN_NOTIMPLEMENTED;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002524 }
2525
2526 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
2527 Py_RETURN_TRUE;
2528 }
2529 Py_RETURN_FALSE;
2530}
2531
Eric Snowab4a1982018-06-13 08:02:39 -06002532static PyObject *
2533_channel_from_cid(PyObject *cid, int end)
2534{
2535 PyObject *highlevel = PyImport_ImportModule("interpreters");
2536 if (highlevel == NULL) {
2537 PyErr_Clear();
2538 highlevel = PyImport_ImportModule("test.support.interpreters");
2539 if (highlevel == NULL) {
2540 return NULL;
2541 }
2542 }
2543 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
2544 "SendChannel";
2545 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
2546 Py_DECREF(highlevel);
2547 if (cls == NULL) {
2548 return NULL;
2549 }
2550 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
2551 Py_DECREF(cls);
2552 if (chan == NULL) {
2553 return NULL;
2554 }
2555 return chan;
2556}
2557
Eric Snow7f8bfc92018-01-29 18:23:44 -07002558struct _channelid_xid {
2559 int64_t id;
2560 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04002561 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002562};
2563
2564static PyObject *
2565_channelid_from_xid(_PyCrossInterpreterData *data)
2566{
2567 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04002568 // Note that we do not preserve the "resolve" flag.
2569 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
2570 _global_channels(), 0, 0);
2571 if (xid->end == 0) {
2572 return cid;
2573 }
2574 if (!xid->resolve) {
2575 return cid;
2576 }
2577
2578 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06002579 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04002580 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06002581 PyErr_Clear();
2582 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04002583 }
2584 Py_DECREF(cid);
2585 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002586}
2587
2588static int
2589_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
2590{
2591 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
2592 if (xid == NULL) {
2593 return -1;
2594 }
2595 xid->id = ((channelid *)obj)->id;
2596 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04002597 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002598
2599 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06002600 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002601 data->obj = obj;
2602 data->new_object = _channelid_from_xid;
2603 data->free = PyMem_Free;
2604 return 0;
2605}
2606
2607static PyObject *
2608channelid_end(PyObject *self, void *end)
2609{
2610 int force = 1;
2611 channelid *cid = (channelid *)self;
2612 if (end != NULL) {
2613 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04002614 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002615 }
2616
2617 if (cid->end == CHANNEL_SEND) {
2618 return PyUnicode_InternFromString("send");
2619 }
2620 if (cid->end == CHANNEL_RECV) {
2621 return PyUnicode_InternFromString("recv");
2622 }
2623 return PyUnicode_InternFromString("both");
2624}
2625
2626static int _channelid_end_send = CHANNEL_SEND;
2627static int _channelid_end_recv = CHANNEL_RECV;
2628
2629static PyGetSetDef channelid_getsets[] = {
2630 {"end", (getter)channelid_end, NULL,
2631 PyDoc_STR("'send', 'recv', or 'both'")},
2632 {"send", (getter)channelid_end, NULL,
2633 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
2634 {"recv", (getter)channelid_end, NULL,
2635 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
2636 {NULL}
2637};
2638
2639PyDoc_STRVAR(channelid_doc,
2640"A channel ID identifies a channel and may be used as an int.");
2641
2642static PyTypeObject ChannelIDtype = {
2643 PyVarObject_HEAD_INIT(&PyType_Type, 0)
2644 "_xxsubinterpreters.ChannelID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02002645 sizeof(channelid), /* tp_basicsize */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002646 0, /* tp_itemsize */
2647 (destructor)channelid_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +02002648 0, /* tp_vectorcall_offset */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002649 0, /* tp_getattr */
2650 0, /* tp_setattr */
2651 0, /* tp_as_async */
2652 (reprfunc)channelid_repr, /* tp_repr */
2653 &channelid_as_number, /* tp_as_number */
2654 0, /* tp_as_sequence */
2655 0, /* tp_as_mapping */
2656 channelid_hash, /* tp_hash */
2657 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04002658 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002659 0, /* tp_getattro */
2660 0, /* tp_setattro */
2661 0, /* tp_as_buffer */
Serhiy Storchakabf169912019-09-13 22:50:27 +03002662 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002663 channelid_doc, /* tp_doc */
2664 0, /* tp_traverse */
2665 0, /* tp_clear */
2666 channelid_richcompare, /* tp_richcompare */
2667 0, /* tp_weaklistoffset */
2668 0, /* tp_iter */
2669 0, /* tp_iternext */
2670 0, /* tp_methods */
2671 0, /* tp_members */
2672 channelid_getsets, /* tp_getset */
2673 0, /* tp_base */
2674 0, /* tp_dict */
2675 0, /* tp_descr_get */
2676 0, /* tp_descr_set */
2677 0, /* tp_dictoffset */
2678 0, /* tp_init */
2679 0, /* tp_alloc */
2680 // Note that we do not set tp_new to channelid_new. Instead we
2681 // set it to NULL, meaning it cannot be instantiated from Python
2682 // code. We do this because there is a strong relationship between
2683 // channel IDs and the channel lifecycle, so this limitation avoids
2684 // related complications.
2685 NULL, /* tp_new */
2686};
2687
Eric Snow4e9da0d2018-02-02 21:49:49 -07002688
2689/* interpreter-specific code ************************************************/
2690
2691static PyObject * RunFailedError = NULL;
2692
2693static int
2694interp_exceptions_init(PyObject *ns)
2695{
2696 // XXX Move the exceptions into per-module memory?
2697
2698 if (RunFailedError == NULL) {
2699 // An uncaught exception came out of interp_run_string().
2700 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
2701 PyExc_RuntimeError, NULL);
2702 if (RunFailedError == NULL) {
2703 return -1;
2704 }
2705 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
2706 return -1;
2707 }
2708 }
2709
2710 return 0;
2711}
Eric Snow7f8bfc92018-01-29 18:23:44 -07002712
Eric Snow7f8bfc92018-01-29 18:23:44 -07002713static int
2714_is_running(PyInterpreterState *interp)
2715{
2716 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2717 if (PyThreadState_Next(tstate) != NULL) {
2718 PyErr_SetString(PyExc_RuntimeError,
2719 "interpreter has more than one thread");
2720 return -1;
2721 }
Victor Stinner4386b902020-04-29 03:01:43 +02002722
2723 assert(!PyErr_Occurred());
Victor Stinner30723382020-03-25 19:52:02 +01002724 PyFrameObject *frame = PyThreadState_GetFrame(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002725 if (frame == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002726 return 0;
2727 }
Victor Stinner4386b902020-04-29 03:01:43 +02002728
2729 int executing = (int)(frame->f_executing);
2730 Py_DECREF(frame);
2731
2732 return executing;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002733}
2734
2735static int
2736_ensure_not_running(PyInterpreterState *interp)
2737{
2738 int is_running = _is_running(interp);
2739 if (is_running < 0) {
2740 return -1;
2741 }
2742 if (is_running) {
2743 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
2744 return -1;
2745 }
2746 return 0;
2747}
2748
2749static int
2750_run_script(PyInterpreterState *interp, const char *codestr,
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002751 _sharedns *shared, _sharedexception **pexc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002752{
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002753 assert(!PyErr_Occurred()); // ...in the called interpreter.
Eric Snow4e9da0d2018-02-02 21:49:49 -07002754
Eric Snowc11183c2019-03-15 16:35:46 -06002755 PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002756 if (main_mod == NULL) {
2757 goto error;
2758 }
2759 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
2760 Py_DECREF(main_mod);
2761 if (ns == NULL) {
2762 goto error;
2763 }
2764 Py_INCREF(ns);
2765
2766 // Apply the cross-interpreter data.
2767 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002768 if (_sharedns_apply(shared, ns) != 0) {
2769 Py_DECREF(ns);
2770 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002771 }
2772 }
2773
2774 // Run the string (see PyRun_SimpleStringFlags).
2775 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
2776 Py_DECREF(ns);
2777 if (result == NULL) {
2778 goto error;
2779 }
2780 else {
2781 Py_DECREF(result); // We throw away the result.
2782 }
2783
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002784 *pexc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002785 return 0;
2786
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002787 PyObject *exctype = NULL, *exc = NULL, *tb = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002788error:
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002789 PyErr_Fetch(&exctype, &exc, &tb);
Eric Snow4e9da0d2018-02-02 21:49:49 -07002790
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002791 // First normalize the exception.
2792 PyErr_NormalizeException(&exctype, &exc, &tb);
2793 assert(PyExceptionInstance_Check(exc));
2794 if (tb != NULL) {
2795 PyException_SetTraceback(exc, tb);
Eric Snow4e9da0d2018-02-02 21:49:49 -07002796 }
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002797
2798 // Behave as though the exception was caught in this thread.
2799 PyErr_SetExcInfo(exctype, exc, tb); // Like entering "except" block.
2800
2801 // Serialize the exception.
2802 _sharedexception *sharedexc = _sharedexception_new();
2803 if (sharedexc == NULL) {
2804 IGNORE_FAILURE("script raised an uncaught exception");
2805 } else {
2806 _sharedexception_extract(sharedexc, exc);
Eric Snow4e9da0d2018-02-02 21:49:49 -07002807 assert(!PyErr_Occurred());
2808 }
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002809
2810 // Clear the exception.
2811 PyErr_SetExcInfo(NULL, NULL, NULL); // Like leaving "except" block.
2812 PyErr_Clear(); // Do not re-raise.
2813
2814 // "Return" the serialized exception.
2815 *pexc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002816 return -1;
2817}
2818
2819static int
2820_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
2821 PyObject *shareables)
2822{
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002823 assert(!PyErr_Occurred()); // ...in the calling interpreter.
2824
Eric Snow7f8bfc92018-01-29 18:23:44 -07002825 if (_ensure_not_running(interp) < 0) {
2826 return -1;
2827 }
2828
Eric Snow4e9da0d2018-02-02 21:49:49 -07002829 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002830 if (shared == NULL && PyErr_Occurred()) {
2831 return -1;
2832 }
2833
Victor Stinnerfb2c7c42020-05-05 20:33:06 +02002834#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
2835 // Switch to interpreter.
2836 PyThreadState *new_tstate = PyInterpreterState_ThreadHead(interp);
2837 PyThreadState *save1 = PyEval_SaveThread();
2838
2839 (void)PyThreadState_Swap(new_tstate);
2840
2841 // Run the script.
2842 _sharedexception *exc = NULL;
2843 int result = _run_script(interp, codestr, shared, &exc);
2844
2845 // Switch back.
2846 PyEval_RestoreThread(save1);
2847#else
Eric Snow7f8bfc92018-01-29 18:23:44 -07002848 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002849 PyThreadState *save_tstate = NULL;
Victor Stinnerbe793732020-03-13 18:15:33 +01002850 if (interp != PyInterpreterState_Get()) {
Eric Snowf53d9f22018-02-20 16:30:17 -07002851 // XXX Using the "head" thread isn't strictly correct.
2852 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2853 // XXX Possible GILState issues?
2854 save_tstate = PyThreadState_Swap(tstate);
2855 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002856
2857 // Run the script.
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002858 _sharedexception *sharedexc = NULL;
2859 int result = _run_script(interp, codestr, shared, &sharedexc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002860
2861 // Switch back.
2862 if (save_tstate != NULL) {
2863 PyThreadState_Swap(save_tstate);
2864 }
Victor Stinnerfb2c7c42020-05-05 20:33:06 +02002865#endif
Eric Snow7f8bfc92018-01-29 18:23:44 -07002866
2867 // Propagate any exception out to the caller.
Eric Snowa1d9e0a2020-05-07 08:56:01 -06002868 if (sharedexc != NULL) {
2869 assert(!PyErr_Occurred());
2870 PyObject *exc = _sharedexception_resolve(sharedexc, RunFailedError);
2871 // XXX This is not safe once interpreters no longer share allocators.
2872 _sharedexception_free(sharedexc);
2873 PyObject *exctype = (PyObject *)Py_TYPE(exc);
2874 Py_INCREF(exctype); // PyErr_Restore() steals a reference.
2875 PyErr_Restore(exctype, exc, PyException_GetTraceback(exc));
Eric Snow7f8bfc92018-01-29 18:23:44 -07002876 }
2877 else if (result != 0) {
2878 // We were unable to allocate a shared exception.
2879 PyErr_NoMemory();
2880 }
2881
2882 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002883 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002884 }
2885
2886 return result;
2887}
2888
2889
2890/* module level code ********************************************************/
2891
2892/* globals is the process-global state for the module. It holds all
2893 the data that we need to share between interpreters, so it cannot
2894 hold PyObject values. */
2895static struct globals {
2896 _channels channels;
2897} _globals = {{0}};
2898
2899static int
2900_init_globals(void)
2901{
2902 if (_channels_init(&_globals.channels) != 0) {
2903 return -1;
2904 }
2905 return 0;
2906}
2907
2908static _channels *
2909_global_channels(void) {
2910 return &_globals.channels;
2911}
2912
2913static PyObject *
Victor Stinner252346a2020-05-01 11:33:44 +02002914interp_create(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002915{
Victor Stinner252346a2020-05-01 11:33:44 +02002916
2917 static char *kwlist[] = {"isolated", NULL};
2918 int isolated = 1;
2919 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$i:create", kwlist,
2920 &isolated)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002921 return NULL;
2922 }
2923
2924 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002925 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2926 // XXX Possible GILState issues?
Victor Stinner252346a2020-05-01 11:33:44 +02002927 PyThreadState *tstate = _Py_NewInterpreter(isolated);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002928 PyThreadState_Swap(save_tstate);
2929 if (tstate == NULL) {
2930 /* Since no new thread state was created, there is no exception to
2931 propagate; raise a fresh one after swapping in the old thread
2932 state. */
2933 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2934 return NULL;
2935 }
Victor Stinner30723382020-03-25 19:52:02 +01002936 PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
2937 PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
Eric Snowc11183c2019-03-15 16:35:46 -06002938 if (idobj == NULL) {
2939 // XXX Possible GILState issues?
2940 save_tstate = PyThreadState_Swap(tstate);
2941 Py_EndInterpreter(tstate);
2942 PyThreadState_Swap(save_tstate);
2943 return NULL;
2944 }
Victor Stinner30723382020-03-25 19:52:02 +01002945 _PyInterpreterState_RequireIDRef(interp, 1);
Eric Snowc11183c2019-03-15 16:35:46 -06002946 return idobj;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002947}
2948
2949PyDoc_STRVAR(create_doc,
2950"create() -> ID\n\
2951\n\
2952Create a new interpreter and return a unique generated ID.");
2953
2954
2955static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002956interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002957{
Eric Snow6d2cd902018-05-16 15:04:57 -04002958 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002959 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002960 // XXX Use "L" for id?
2961 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2962 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002963 return NULL;
2964 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002965
2966 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06002967 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002968 if (interp == NULL) {
2969 return NULL;
2970 }
2971
2972 // Ensure we don't try to destroy the current interpreter.
2973 PyInterpreterState *current = _get_current();
2974 if (current == NULL) {
2975 return NULL;
2976 }
2977 if (interp == current) {
2978 PyErr_SetString(PyExc_RuntimeError,
2979 "cannot destroy the current interpreter");
2980 return NULL;
2981 }
2982
2983 // Ensure the interpreter isn't running.
2984 /* XXX We *could* support destroying a running interpreter but
2985 aren't going to worry about it for now. */
2986 if (_ensure_not_running(interp) < 0) {
2987 return NULL;
2988 }
2989
2990 // Destroy the interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002991 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2992 // XXX Possible GILState issues?
2993 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002994 Py_EndInterpreter(tstate);
2995 PyThreadState_Swap(save_tstate);
2996
2997 Py_RETURN_NONE;
2998}
2999
3000PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04003001"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003002\n\
3003Destroy the identified interpreter.\n\
3004\n\
3005Attempting to destroy the current interpreter results in a RuntimeError.\n\
3006So does an unrecognized ID.");
3007
3008
3009static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303010interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07003011{
3012 PyObject *ids, *id;
3013 PyInterpreterState *interp;
3014
3015 ids = PyList_New(0);
3016 if (ids == NULL) {
3017 return NULL;
3018 }
3019
3020 interp = PyInterpreterState_Head();
3021 while (interp != NULL) {
Eric Snowc11183c2019-03-15 16:35:46 -06003022 id = _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003023 if (id == NULL) {
3024 Py_DECREF(ids);
3025 return NULL;
3026 }
3027 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07003028 int res = PyList_Insert(ids, 0, id);
3029 Py_DECREF(id);
3030 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003031 Py_DECREF(ids);
3032 return NULL;
3033 }
3034
3035 interp = PyInterpreterState_Next(interp);
3036 }
3037
3038 return ids;
3039}
3040
3041PyDoc_STRVAR(list_all_doc,
3042"list_all() -> [ID]\n\
3043\n\
3044Return a list containing the ID of every existing interpreter.");
3045
3046
3047static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303048interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07003049{
3050 PyInterpreterState *interp =_get_current();
3051 if (interp == NULL) {
3052 return NULL;
3053 }
Eric Snowc11183c2019-03-15 16:35:46 -06003054 return _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003055}
3056
3057PyDoc_STRVAR(get_current_doc,
3058"get_current() -> ID\n\
3059\n\
3060Return the ID of current interpreter.");
3061
3062
3063static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303064interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07003065{
3066 // Currently, 0 is always the main interpreter.
Victor Stinner1a1bd2e2020-04-17 19:13:06 +02003067 int64_t id = 0;
Eric Snowc11183c2019-03-15 16:35:46 -06003068 return _PyInterpreterID_New(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003069}
3070
3071PyDoc_STRVAR(get_main_doc,
3072"get_main() -> ID\n\
3073\n\
3074Return the ID of main interpreter.");
3075
3076
3077static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003078interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003079{
Eric Snow6d2cd902018-05-16 15:04:57 -04003080 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07003081 PyObject *id, *code;
3082 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04003083 if (!PyArg_ParseTupleAndKeywords(args, kwds,
3084 "OU|O:run_string", kwlist,
3085 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003086 return NULL;
3087 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07003088
3089 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06003090 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003091 if (interp == NULL) {
3092 return NULL;
3093 }
3094
3095 // Extract code.
3096 Py_ssize_t size;
3097 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
3098 if (codestr == NULL) {
3099 return NULL;
3100 }
3101 if (strlen(codestr) != (size_t)size) {
3102 PyErr_SetString(PyExc_ValueError,
3103 "source code string cannot contain null bytes");
3104 return NULL;
3105 }
3106
3107 // Run the code in the interpreter.
3108 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
3109 return NULL;
3110 }
3111 Py_RETURN_NONE;
3112}
3113
3114PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04003115"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003116\n\
3117Execute the provided string in the identified interpreter.\n\
3118\n\
3119See PyRun_SimpleStrings.");
3120
3121
3122static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003123object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003124{
Eric Snow6d2cd902018-05-16 15:04:57 -04003125 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07003126 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04003127 if (!PyArg_ParseTupleAndKeywords(args, kwds,
3128 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003129 return NULL;
3130 }
Eric Snow6d2cd902018-05-16 15:04:57 -04003131
Eric Snow7f8bfc92018-01-29 18:23:44 -07003132 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
3133 Py_RETURN_TRUE;
3134 }
3135 PyErr_Clear();
3136 Py_RETURN_FALSE;
3137}
3138
3139PyDoc_STRVAR(is_shareable_doc,
3140"is_shareable(obj) -> bool\n\
3141\n\
3142Return True if the object's data may be shared between interpreters and\n\
3143False otherwise.");
3144
3145
3146static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003147interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003148{
Eric Snow6d2cd902018-05-16 15:04:57 -04003149 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07003150 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04003151 if (!PyArg_ParseTupleAndKeywords(args, kwds,
3152 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003153 return NULL;
3154 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07003155
Eric Snowc11183c2019-03-15 16:35:46 -06003156 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003157 if (interp == NULL) {
3158 return NULL;
3159 }
3160 int is_running = _is_running(interp);
3161 if (is_running < 0) {
3162 return NULL;
3163 }
3164 if (is_running) {
3165 Py_RETURN_TRUE;
3166 }
3167 Py_RETURN_FALSE;
3168}
3169
3170PyDoc_STRVAR(is_running_doc,
3171"is_running(id) -> bool\n\
3172\n\
3173Return whether or not the identified interpreter is running.");
3174
3175static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303176channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07003177{
3178 int64_t cid = _channel_create(&_globals.channels);
3179 if (cid < 0) {
3180 return NULL;
3181 }
3182 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04003183 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003184 if (id == NULL) {
3185 if (_channel_destroy(&_globals.channels, cid) != 0) {
3186 // XXX issue a warning?
3187 }
3188 return NULL;
3189 }
3190 assert(((channelid *)id)->channels != NULL);
3191 return id;
3192}
3193
3194PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04003195"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003196\n\
3197Create a new cross-interpreter channel and return a unique generated ID.");
3198
3199static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003200channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003201{
Eric Snow6d2cd902018-05-16 15:04:57 -04003202 static char *kwlist[] = {"cid", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03003203 int64_t cid;
3204 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_destroy", kwlist,
3205 channel_id_converter, &cid)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003206 return NULL;
3207 }
3208
3209 if (_channel_destroy(&_globals.channels, cid) != 0) {
3210 return NULL;
3211 }
3212 Py_RETURN_NONE;
3213}
3214
3215PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04003216"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003217\n\
3218Close and finalize the channel. Afterward attempts to use the channel\n\
3219will behave as though it never existed.");
3220
3221static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303222channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07003223{
3224 int64_t count = 0;
3225 int64_t *cids = _channels_list_all(&_globals.channels, &count);
3226 if (cids == NULL) {
3227 if (count == 0) {
3228 return PyList_New(0);
3229 }
3230 return NULL;
3231 }
3232 PyObject *ids = PyList_New((Py_ssize_t)count);
3233 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07003234 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07003235 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07003236 int64_t *cur = cids;
3237 for (int64_t i=0; i < count; cur++, i++) {
3238 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04003239 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003240 if (id == NULL) {
3241 Py_DECREF(ids);
3242 ids = NULL;
3243 break;
3244 }
3245 PyList_SET_ITEM(ids, i, id);
3246 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07003247
3248finally:
3249 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003250 return ids;
3251}
3252
3253PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04003254"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003255\n\
3256Return the list of all IDs for active channels.");
3257
3258static PyObject *
Lewis Gaulf7bbf582020-04-29 01:18:42 +01003259channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
3260{
3261 static char *kwlist[] = {"cid", "send", NULL};
3262 int64_t cid; /* Channel ID */
3263 int send = 0; /* Send or receive end? */
3264 int64_t id;
3265 PyObject *ids, *id_obj;
3266 PyInterpreterState *interp;
3267
3268 if (!PyArg_ParseTupleAndKeywords(
3269 args, kwds, "O&$p:channel_list_interpreters",
3270 kwlist, channel_id_converter, &cid, &send)) {
3271 return NULL;
3272 }
3273
3274 ids = PyList_New(0);
3275 if (ids == NULL) {
3276 goto except;
3277 }
3278
3279 interp = PyInterpreterState_Head();
3280 while (interp != NULL) {
3281 id = PyInterpreterState_GetID(interp);
3282 assert(id >= 0);
3283 int res = _channel_is_associated(&_globals.channels, cid, id, send);
3284 if (res < 0) {
3285 goto except;
3286 }
3287 if (res) {
3288 id_obj = _PyInterpreterState_GetIDObject(interp);
3289 if (id_obj == NULL) {
3290 goto except;
3291 }
3292 res = PyList_Insert(ids, 0, id_obj);
3293 Py_DECREF(id_obj);
3294 if (res < 0) {
3295 goto except;
3296 }
3297 }
3298 interp = PyInterpreterState_Next(interp);
3299 }
3300
3301 goto finally;
3302
3303except:
3304 Py_XDECREF(ids);
3305 ids = NULL;
3306
3307finally:
3308 return ids;
3309}
3310
3311PyDoc_STRVAR(channel_list_interpreters_doc,
3312"channel_list_interpreters(cid, *, send) -> [id]\n\
3313\n\
3314Return the list of all interpreter IDs associated with an end of the channel.\n\
3315\n\
3316The 'send' argument should be a boolean indicating whether to use the send or\n\
3317receive end.");
3318
3319
3320static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003321channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003322{
Eric Snow6d2cd902018-05-16 15:04:57 -04003323 static char *kwlist[] = {"cid", "obj", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03003324 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07003325 PyObject *obj;
Serhiy Storchakabf169912019-09-13 22:50:27 +03003326 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O:channel_send", kwlist,
3327 channel_id_converter, &cid, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003328 return NULL;
3329 }
3330
3331 if (_channel_send(&_globals.channels, cid, obj) != 0) {
3332 return NULL;
3333 }
3334 Py_RETURN_NONE;
3335}
3336
3337PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04003338"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003339\n\
3340Add the object's data to the channel's queue.");
3341
3342static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003343channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003344{
Eric Snow5e8c6912020-04-28 17:11:32 -06003345 static char *kwlist[] = {"cid", "default", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03003346 int64_t cid;
Eric Snow5e8c6912020-04-28 17:11:32 -06003347 PyObject *dflt = NULL;
3348 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O:channel_recv", kwlist,
3349 channel_id_converter, &cid, &dflt)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003350 return NULL;
3351 }
Eric Snow5e8c6912020-04-28 17:11:32 -06003352 Py_XINCREF(dflt);
Eric Snow7f8bfc92018-01-29 18:23:44 -07003353
Eric Snow5e8c6912020-04-28 17:11:32 -06003354 PyObject *obj = _channel_recv(&_globals.channels, cid);
3355 if (obj != NULL) {
3356 Py_XDECREF(dflt);
3357 return obj;
3358 } else if (PyErr_Occurred()) {
3359 Py_XDECREF(dflt);
3360 return NULL;
3361 } else if (dflt != NULL) {
3362 return dflt;
3363 } else {
3364 PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", cid);
3365 return NULL;
3366 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07003367}
3368
3369PyDoc_STRVAR(channel_recv_doc,
Eric Snow5e8c6912020-04-28 17:11:32 -06003370"channel_recv(cid, [default]) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003371\n\
Eric Snow5e8c6912020-04-28 17:11:32 -06003372Return a new object from the data at the front of the channel's queue.\n\
3373\n\
3374If there is nothing to receive then raise ChannelEmptyError, unless\n\
3375a default value is provided. In that case return it.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07003376
3377static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003378channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003379{
Eric Snow6d2cd902018-05-16 15:04:57 -04003380 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03003381 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04003382 int send = 0;
3383 int recv = 0;
3384 int force = 0;
3385 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03003386 "O&|$ppp:channel_close", kwlist,
3387 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003388 return NULL;
3389 }
Eric Snow6d2cd902018-05-16 15:04:57 -04003390
Eric Snow3ab01362018-05-17 10:27:09 -04003391 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003392 return NULL;
3393 }
3394 Py_RETURN_NONE;
3395}
3396
3397PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04003398"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003399\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04003400Close the channel for all interpreters.\n\
3401\n\
3402If the channel is empty then the keyword args are ignored and both\n\
3403ends are immediately closed. Otherwise, if 'force' is True then\n\
3404all queued items are released and both ends are immediately\n\
3405closed.\n\
3406\n\
3407If the channel is not empty *and* 'force' is False then following\n\
3408happens:\n\
3409\n\
3410 * recv is True (regardless of send):\n\
3411 - raise ChannelNotEmptyError\n\
3412 * recv is None and send is None:\n\
3413 - raise ChannelNotEmptyError\n\
3414 * send is True and recv is not True:\n\
3415 - fully close the 'send' end\n\
3416 - close the 'recv' end to interpreters not already receiving\n\
3417 - fully close it once empty\n\
3418\n\
3419Closing an already closed channel results in a ChannelClosedError.\n\
3420\n\
3421Once the channel's ID has no more ref counts in any interpreter\n\
3422the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07003423
3424static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04003425channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07003426{
3427 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04003428 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03003429 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04003430 int send = 0;
3431 int recv = 0;
3432 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07003433 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03003434 "O&|$ppp:channel_release", kwlist,
3435 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003436 return NULL;
3437 }
Eric Snow6d2cd902018-05-16 15:04:57 -04003438 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003439 send = 1;
3440 recv = 1;
3441 }
Eric Snow6d2cd902018-05-16 15:04:57 -04003442
3443 // XXX Handle force is True.
3444 // XXX Fix implicit release.
3445
Eric Snow7f8bfc92018-01-29 18:23:44 -07003446 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
3447 return NULL;
3448 }
3449 Py_RETURN_NONE;
3450}
3451
Eric Snow6d2cd902018-05-16 15:04:57 -04003452PyDoc_STRVAR(channel_release_doc,
3453"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07003454\n\
3455Close the channel for the current interpreter. 'send' and 'recv'\n\
3456(bool) may be used to indicate the ends to close. By default both\n\
3457ends are closed. Closing an already closed end is a noop.");
3458
3459static PyObject *
3460channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
3461{
3462 return channelid_new(&ChannelIDtype, args, kwds);
3463}
3464
3465static PyMethodDef module_functions[] = {
Victor Stinner252346a2020-05-01 11:33:44 +02003466 {"create", (PyCFunction)(void(*)(void))interp_create,
3467 METH_VARARGS | METH_KEYWORDS, create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003468 {"destroy", (PyCFunction)(void(*)(void))interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04003469 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303470 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07003471 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303472 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07003473 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303474 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07003475 METH_NOARGS, get_main_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003476 {"is_running", (PyCFunction)(void(*)(void))interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04003477 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003478 {"run_string", (PyCFunction)(void(*)(void))interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04003479 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07003480
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003481 {"is_shareable", (PyCFunction)(void(*)(void))object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04003482 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07003483
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303484 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07003485 METH_NOARGS, channel_create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003486 {"channel_destroy", (PyCFunction)(void(*)(void))channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04003487 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05303488 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07003489 METH_NOARGS, channel_list_all_doc},
Lewis Gaulf7bbf582020-04-29 01:18:42 +01003490 {"channel_list_interpreters", (PyCFunction)(void(*)(void))channel_list_interpreters,
3491 METH_VARARGS | METH_KEYWORDS, channel_list_interpreters_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003492 {"channel_send", (PyCFunction)(void(*)(void))channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04003493 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003494 {"channel_recv", (PyCFunction)(void(*)(void))channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04003495 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003496 {"channel_close", (PyCFunction)(void(*)(void))channel_close,
Eric Snow6d2cd902018-05-16 15:04:57 -04003497 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003498 {"channel_release", (PyCFunction)(void(*)(void))channel_release,
Eric Snow6d2cd902018-05-16 15:04:57 -04003499 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02003500 {"_channel_id", (PyCFunction)(void(*)(void))channel__channel_id,
Eric Snow7f8bfc92018-01-29 18:23:44 -07003501 METH_VARARGS | METH_KEYWORDS, NULL},
3502
3503 {NULL, NULL} /* sentinel */
3504};
3505
3506
3507/* initialization function */
3508
3509PyDoc_STRVAR(module_doc,
3510"This module provides primitive operations to manage Python interpreters.\n\
3511The 'interpreters' module provides a more convenient interface.");
3512
3513static struct PyModuleDef interpretersmodule = {
3514 PyModuleDef_HEAD_INIT,
3515 "_xxsubinterpreters", /* m_name */
3516 module_doc, /* m_doc */
3517 -1, /* m_size */
3518 module_functions, /* m_methods */
3519 NULL, /* m_slots */
3520 NULL, /* m_traverse */
3521 NULL, /* m_clear */
3522 NULL /* m_free */
3523};
3524
3525
3526PyMODINIT_FUNC
3527PyInit__xxsubinterpreters(void)
3528{
3529 if (_init_globals() != 0) {
3530 return NULL;
3531 }
3532
3533 /* Initialize types */
Eric Snow7f8bfc92018-01-29 18:23:44 -07003534 if (PyType_Ready(&ChannelIDtype) != 0) {
3535 return NULL;
3536 }
3537
3538 /* Create the module */
3539 PyObject *module = PyModule_Create(&interpretersmodule);
3540 if (module == NULL) {
3541 return NULL;
3542 }
3543
3544 /* Add exception types */
3545 PyObject *ns = PyModule_GetDict(module); // borrowed
3546 if (interp_exceptions_init(ns) != 0) {
3547 return NULL;
3548 }
3549 if (channel_exceptions_init(ns) != 0) {
3550 return NULL;
3551 }
3552
3553 /* Add other types */
3554 Py_INCREF(&ChannelIDtype);
3555 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
3556 return NULL;
3557 }
Eric Snowc11183c2019-03-15 16:35:46 -06003558 Py_INCREF(&_PyInterpreterID_Type);
3559 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&_PyInterpreterID_Type) != 0) {
Eric Snow4c6955e2018-02-16 18:53:40 -07003560 return NULL;
3561 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07003562
Eric Snowc11183c2019-03-15 16:35:46 -06003563 if (_PyCrossInterpreterData_RegisterClass(&ChannelIDtype, _channelid_shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07003564 return NULL;
3565 }
3566
3567 return module;
3568}