blob: fa20bc5dcec57e9eb6fb09a90c7e10b92801e7e4 [file] [log] [blame]
Eric Snow7f8bfc92018-01-29 18:23:44 -07001
2/* interpreters module */
3/* low-level access to interpreter primitives */
4
5#include "Python.h"
6#include "frameobject.h"
Eric Snowc11183c2019-03-15 16:35:46 -06007#include "interpreteridobject.h"
Eric Snow7f8bfc92018-01-29 18:23:44 -07008
9
Eric Snow4e9da0d2018-02-02 21:49:49 -070010static char *
11_copy_raw_string(PyObject *strobj)
12{
13 const char *str = PyUnicode_AsUTF8(strobj);
14 if (str == NULL) {
15 return NULL;
16 }
17 char *copied = PyMem_Malloc(strlen(str)+1);
Alexey Izbyshevc5839192018-08-22 21:27:32 +030018 if (copied == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070019 PyErr_NoMemory();
20 return NULL;
21 }
22 strcpy(copied, str);
23 return copied;
24}
25
Eric Snow7f8bfc92018-01-29 18:23:44 -070026static PyInterpreterState *
27_get_current(void)
28{
Victor Stinnercaba55b2018-08-03 15:33:52 +020029 // _PyInterpreterState_Get() aborts if lookup fails, so don't need
Eric Snow7f8bfc92018-01-29 18:23:44 -070030 // to check the result for NULL.
Victor Stinnercaba55b2018-08-03 15:33:52 +020031 return _PyInterpreterState_Get();
Eric Snow7f8bfc92018-01-29 18:23:44 -070032}
33
Eric Snow4e9da0d2018-02-02 21:49:49 -070034
Eric Snow7f8bfc92018-01-29 18:23:44 -070035/* data-sharing-specific code ***********************************************/
36
Eric Snow4e9da0d2018-02-02 21:49:49 -070037struct _sharednsitem {
38 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -070039 _PyCrossInterpreterData data;
Eric Snow4e9da0d2018-02-02 21:49:49 -070040};
Eric Snow7f8bfc92018-01-29 18:23:44 -070041
Eric Snowc11183c2019-03-15 16:35:46 -060042static void _sharednsitem_clear(struct _sharednsitem *); // forward
43
Eric Snow4e9da0d2018-02-02 21:49:49 -070044static int
45_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
Eric Snow7f8bfc92018-01-29 18:23:44 -070046{
Eric Snow4e9da0d2018-02-02 21:49:49 -070047 item->name = _copy_raw_string(key);
48 if (item->name == NULL) {
49 return -1;
Eric Snow7f8bfc92018-01-29 18:23:44 -070050 }
Eric Snow4e9da0d2018-02-02 21:49:49 -070051 if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
Eric Snowc11183c2019-03-15 16:35:46 -060052 _sharednsitem_clear(item);
Eric Snow4e9da0d2018-02-02 21:49:49 -070053 return -1;
54 }
55 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -070056}
57
Eric Snow4e9da0d2018-02-02 21:49:49 -070058static void
59_sharednsitem_clear(struct _sharednsitem *item)
60{
61 if (item->name != NULL) {
62 PyMem_Free(item->name);
Eric Snowc11183c2019-03-15 16:35:46 -060063 item->name = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -070064 }
65 _PyCrossInterpreterData_Release(&item->data);
66}
67
68static int
69_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
70{
71 PyObject *name = PyUnicode_FromString(item->name);
72 if (name == NULL) {
73 return -1;
74 }
75 PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
76 if (value == NULL) {
77 Py_DECREF(name);
78 return -1;
79 }
80 int res = PyDict_SetItem(ns, name, value);
81 Py_DECREF(name);
82 Py_DECREF(value);
83 return res;
84}
85
86typedef struct _sharedns {
87 Py_ssize_t len;
88 struct _sharednsitem* items;
89} _sharedns;
90
91static _sharedns *
92_sharedns_new(Py_ssize_t len)
93{
94 _sharedns *shared = PyMem_NEW(_sharedns, 1);
95 if (shared == NULL) {
96 PyErr_NoMemory();
97 return NULL;
98 }
99 shared->len = len;
100 shared->items = PyMem_NEW(struct _sharednsitem, len);
101 if (shared->items == NULL) {
102 PyErr_NoMemory();
103 PyMem_Free(shared);
104 return NULL;
105 }
106 return shared;
107}
108
109static void
110_sharedns_free(_sharedns *shared)
111{
112 for (Py_ssize_t i=0; i < shared->len; i++) {
113 _sharednsitem_clear(&shared->items[i]);
114 }
115 PyMem_Free(shared->items);
116 PyMem_Free(shared);
117}
118
119static _sharedns *
120_get_shared_ns(PyObject *shareable)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700121{
122 if (shareable == NULL || shareable == Py_None) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700123 return NULL;
124 }
125 Py_ssize_t len = PyDict_Size(shareable);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700126 if (len == 0) {
127 return NULL;
128 }
129
Eric Snow4e9da0d2018-02-02 21:49:49 -0700130 _sharedns *shared = _sharedns_new(len);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700131 if (shared == NULL) {
132 return NULL;
133 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700134 Py_ssize_t pos = 0;
135 for (Py_ssize_t i=0; i < len; i++) {
136 PyObject *key, *value;
137 if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
138 break;
139 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700140 if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700141 break;
142 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700143 }
144 if (PyErr_Occurred()) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700145 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700146 return NULL;
147 }
148 return shared;
149}
150
151static int
Eric Snow4e9da0d2018-02-02 21:49:49 -0700152_sharedns_apply(_sharedns *shared, PyObject *ns)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700153{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700154 for (Py_ssize_t i=0; i < shared->len; i++) {
155 if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
156 return -1;
157 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700158 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700159 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700160}
161
162// Ultimately we'd like to preserve enough information about the
163// exception and traceback that we could re-constitute (or at least
164// simulate, a la traceback.TracebackException), and even chain, a copy
165// of the exception in the calling interpreter.
166
167typedef struct _sharedexception {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700168 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700169 char *msg;
170} _sharedexception;
171
172static _sharedexception *
Eric Snow4e9da0d2018-02-02 21:49:49 -0700173_sharedexception_new(void)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700174{
175 _sharedexception *err = PyMem_NEW(_sharedexception, 1);
176 if (err == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700177 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700178 return NULL;
179 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700180 err->name = NULL;
181 err->msg = NULL;
182 return err;
183}
184
185static void
186_sharedexception_clear(_sharedexception *exc)
187{
188 if (exc->name != NULL) {
189 PyMem_Free(exc->name);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700190 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700191 if (exc->msg != NULL) {
192 PyMem_Free(exc->msg);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700193 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700194}
195
196static void
197_sharedexception_free(_sharedexception *exc)
198{
199 _sharedexception_clear(exc);
200 PyMem_Free(exc);
201}
202
203static _sharedexception *
204_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
205{
206 assert(exctype != NULL);
207 char *failure = NULL;
208
209 _sharedexception *err = _sharedexception_new();
210 if (err == NULL) {
211 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700212 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700213
214 PyObject *name = PyUnicode_FromFormat("%S", exctype);
215 if (name == NULL) {
216 failure = "unable to format exception type name";
217 goto finally;
218 }
219 err->name = _copy_raw_string(name);
220 Py_DECREF(name);
221 if (err->name == NULL) {
222 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
223 failure = "out of memory copying exception type name";
Alex Henrie5cae0422020-01-09 02:48:52 +0000224 } else {
225 failure = "unable to encode and copy exception type name";
Eric Snow4e9da0d2018-02-02 21:49:49 -0700226 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700227 goto finally;
228 }
229
230 if (exc != NULL) {
231 PyObject *msg = PyUnicode_FromFormat("%S", exc);
232 if (msg == NULL) {
233 failure = "unable to format exception message";
234 goto finally;
235 }
236 err->msg = _copy_raw_string(msg);
237 Py_DECREF(msg);
238 if (err->msg == NULL) {
239 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
240 failure = "out of memory copying exception message";
Alex Henrie5cae0422020-01-09 02:48:52 +0000241 } else {
242 failure = "unable to encode and copy exception message";
Eric Snow4e9da0d2018-02-02 21:49:49 -0700243 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700244 goto finally;
245 }
246 }
247
248finally:
249 if (failure != NULL) {
250 PyErr_Clear();
251 if (err->name != NULL) {
252 PyMem_Free(err->name);
253 err->name = NULL;
254 }
255 err->msg = failure;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700256 }
257 return err;
258}
259
Eric Snow7f8bfc92018-01-29 18:23:44 -0700260static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700261_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700262{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700263 if (exc->name != NULL) {
264 if (exc->msg != NULL) {
265 PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
266 }
267 else {
268 PyErr_SetString(wrapperclass, exc->name);
269 }
270 }
271 else if (exc->msg != NULL) {
272 PyErr_SetString(wrapperclass, exc->msg);
273 }
274 else {
275 PyErr_SetNone(wrapperclass);
276 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700277}
278
Eric Snow4e9da0d2018-02-02 21:49:49 -0700279
280/* channel-specific code ****************************************************/
Eric Snow7f8bfc92018-01-29 18:23:44 -0700281
Eric Snow3ab01362018-05-17 10:27:09 -0400282#define CHANNEL_SEND 1
283#define CHANNEL_BOTH 0
284#define CHANNEL_RECV -1
285
Eric Snow7f8bfc92018-01-29 18:23:44 -0700286static PyObject *ChannelError;
287static PyObject *ChannelNotFoundError;
288static PyObject *ChannelClosedError;
289static PyObject *ChannelEmptyError;
Eric Snow3ab01362018-05-17 10:27:09 -0400290static PyObject *ChannelNotEmptyError;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700291
292static int
293channel_exceptions_init(PyObject *ns)
294{
295 // XXX Move the exceptions into per-module memory?
296
297 // A channel-related operation failed.
298 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
299 PyExc_RuntimeError, NULL);
300 if (ChannelError == NULL) {
301 return -1;
302 }
303 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
304 return -1;
305 }
306
307 // An operation tried to use a channel that doesn't exist.
308 ChannelNotFoundError = PyErr_NewException(
309 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
310 if (ChannelNotFoundError == NULL) {
311 return -1;
312 }
313 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
314 return -1;
315 }
316
317 // An operation tried to use a closed channel.
318 ChannelClosedError = PyErr_NewException(
319 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
320 if (ChannelClosedError == NULL) {
321 return -1;
322 }
323 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
324 return -1;
325 }
326
327 // An operation tried to pop from an empty channel.
328 ChannelEmptyError = PyErr_NewException(
329 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
330 if (ChannelEmptyError == NULL) {
331 return -1;
332 }
333 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
334 return -1;
335 }
336
Eric Snow3ab01362018-05-17 10:27:09 -0400337 // An operation tried to close a non-empty channel.
338 ChannelNotEmptyError = PyErr_NewException(
339 "_xxsubinterpreters.ChannelNotEmptyError", ChannelError, NULL);
340 if (ChannelNotEmptyError == NULL) {
341 return -1;
342 }
343 if (PyDict_SetItemString(ns, "ChannelNotEmptyError", ChannelNotEmptyError) != 0) {
344 return -1;
345 }
346
Eric Snow7f8bfc92018-01-29 18:23:44 -0700347 return 0;
348}
349
Eric Snow4e9da0d2018-02-02 21:49:49 -0700350/* the channel queue */
351
352struct _channelitem;
353
354typedef struct _channelitem {
355 _PyCrossInterpreterData *data;
356 struct _channelitem *next;
357} _channelitem;
358
359static _channelitem *
360_channelitem_new(void)
361{
362 _channelitem *item = PyMem_NEW(_channelitem, 1);
363 if (item == NULL) {
364 PyErr_NoMemory();
365 return NULL;
366 }
367 item->data = NULL;
368 item->next = NULL;
369 return item;
370}
371
372static void
373_channelitem_clear(_channelitem *item)
374{
375 if (item->data != NULL) {
376 _PyCrossInterpreterData_Release(item->data);
377 PyMem_Free(item->data);
378 item->data = NULL;
379 }
380 item->next = NULL;
381}
382
383static void
384_channelitem_free(_channelitem *item)
385{
386 _channelitem_clear(item);
387 PyMem_Free(item);
388}
389
390static void
391_channelitem_free_all(_channelitem *item)
392{
393 while (item != NULL) {
394 _channelitem *last = item;
395 item = item->next;
396 _channelitem_free(last);
397 }
398}
399
400static _PyCrossInterpreterData *
401_channelitem_popped(_channelitem *item)
402{
403 _PyCrossInterpreterData *data = item->data;
404 item->data = NULL;
405 _channelitem_free(item);
406 return data;
407}
408
409typedef struct _channelqueue {
410 int64_t count;
411 _channelitem *first;
412 _channelitem *last;
413} _channelqueue;
414
415static _channelqueue *
416_channelqueue_new(void)
417{
418 _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
419 if (queue == NULL) {
420 PyErr_NoMemory();
421 return NULL;
422 }
423 queue->count = 0;
424 queue->first = NULL;
425 queue->last = NULL;
426 return queue;
427}
428
429static void
430_channelqueue_clear(_channelqueue *queue)
431{
432 _channelitem_free_all(queue->first);
433 queue->count = 0;
434 queue->first = NULL;
435 queue->last = NULL;
436}
437
438static void
439_channelqueue_free(_channelqueue *queue)
440{
441 _channelqueue_clear(queue);
442 PyMem_Free(queue);
443}
444
445static int
446_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
447{
448 _channelitem *item = _channelitem_new();
449 if (item == NULL) {
450 return -1;
451 }
452 item->data = data;
453
454 queue->count += 1;
455 if (queue->first == NULL) {
456 queue->first = item;
457 }
458 else {
459 queue->last->next = item;
460 }
461 queue->last = item;
462 return 0;
463}
464
465static _PyCrossInterpreterData *
466_channelqueue_get(_channelqueue *queue)
467{
468 _channelitem *item = queue->first;
469 if (item == NULL) {
470 return NULL;
471 }
472 queue->first = item->next;
473 if (queue->last == item) {
474 queue->last = NULL;
475 }
476 queue->count -= 1;
477
478 return _channelitem_popped(item);
479}
480
481/* channel-interpreter associations */
482
Eric Snow7f8bfc92018-01-29 18:23:44 -0700483struct _channelend;
484
485typedef struct _channelend {
486 struct _channelend *next;
487 int64_t interp;
488 int open;
489} _channelend;
490
491static _channelend *
492_channelend_new(int64_t interp)
493{
494 _channelend *end = PyMem_NEW(_channelend, 1);
495 if (end == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700496 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700497 return NULL;
498 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700499 end->next = NULL;
500 end->interp = interp;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700501 end->open = 1;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700502 return end;
503}
504
505static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700506_channelend_free(_channelend *end)
507{
508 PyMem_Free(end);
509}
510
511static void
512_channelend_free_all(_channelend *end)
513{
Eric Snow7f8bfc92018-01-29 18:23:44 -0700514 while (end != NULL) {
515 _channelend *last = end;
516 end = end->next;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700517 _channelend_free(last);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700518 }
519}
520
521static _channelend *
522_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
523{
524 _channelend *prev = NULL;
525 _channelend *end = first;
526 while (end != NULL) {
527 if (end->interp == interp) {
528 break;
529 }
530 prev = end;
531 end = end->next;
532 }
533 if (pprev != NULL) {
534 *pprev = prev;
535 }
536 return end;
537}
538
Eric Snow4e9da0d2018-02-02 21:49:49 -0700539typedef struct _channelassociations {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700540 // Note that the list entries are never removed for interpreter
541 // for which the channel is closed. This should be a problem in
542 // practice. Also, a channel isn't automatically closed when an
543 // interpreter is destroyed.
544 int64_t numsendopen;
545 int64_t numrecvopen;
546 _channelend *send;
547 _channelend *recv;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700548} _channelends;
549
550static _channelends *
551_channelends_new(void)
552{
553 _channelends *ends = PyMem_NEW(_channelends, 1);
554 if (ends== NULL) {
555 return NULL;
556 }
557 ends->numsendopen = 0;
558 ends->numrecvopen = 0;
559 ends->send = NULL;
560 ends->recv = NULL;
561 return ends;
562}
563
564static void
565_channelends_clear(_channelends *ends)
566{
567 _channelend_free_all(ends->send);
568 ends->send = NULL;
569 ends->numsendopen = 0;
570
571 _channelend_free_all(ends->recv);
572 ends->recv = NULL;
573 ends->numrecvopen = 0;
574}
575
576static void
577_channelends_free(_channelends *ends)
578{
579 _channelends_clear(ends);
580 PyMem_Free(ends);
581}
582
583static _channelend *
584_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
585 int send)
586{
587 _channelend *end = _channelend_new(interp);
588 if (end == NULL) {
589 return NULL;
590 }
591
592 if (prev == NULL) {
593 if (send) {
594 ends->send = end;
595 }
596 else {
597 ends->recv = end;
598 }
599 }
600 else {
601 prev->next = end;
602 }
603 if (send) {
604 ends->numsendopen += 1;
605 }
606 else {
607 ends->numrecvopen += 1;
608 }
609 return end;
610}
611
612static int
613_channelends_associate(_channelends *ends, int64_t interp, int send)
614{
615 _channelend *prev;
616 _channelend *end = _channelend_find(send ? ends->send : ends->recv,
617 interp, &prev);
618 if (end != NULL) {
619 if (!end->open) {
620 PyErr_SetString(ChannelClosedError, "channel already closed");
621 return -1;
622 }
623 // already associated
624 return 0;
625 }
626 if (_channelends_add(ends, prev, interp, send) == NULL) {
627 return -1;
628 }
629 return 0;
630}
631
632static int
633_channelends_is_open(_channelends *ends)
634{
635 if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
636 return 1;
637 }
638 if (ends->send == NULL && ends->recv == NULL) {
639 return 1;
640 }
641 return 0;
642}
643
644static void
645_channelends_close_end(_channelends *ends, _channelend *end, int send)
646{
647 end->open = 0;
648 if (send) {
649 ends->numsendopen -= 1;
650 }
651 else {
652 ends->numrecvopen -= 1;
653 }
654}
655
656static int
657_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
658{
659 _channelend *prev;
660 _channelend *end;
661 if (which >= 0) { // send/both
662 end = _channelend_find(ends->send, interp, &prev);
663 if (end == NULL) {
664 // never associated so add it
665 end = _channelends_add(ends, prev, interp, 1);
666 if (end == NULL) {
667 return -1;
668 }
669 }
670 _channelends_close_end(ends, end, 1);
671 }
672 if (which <= 0) { // recv/both
673 end = _channelend_find(ends->recv, interp, &prev);
674 if (end == NULL) {
675 // never associated so add it
676 end = _channelends_add(ends, prev, interp, 0);
677 if (end == NULL) {
678 return -1;
679 }
680 }
681 _channelends_close_end(ends, end, 0);
682 }
683 return 0;
684}
685
686static void
Eric Snow3ab01362018-05-17 10:27:09 -0400687_channelends_close_all(_channelends *ends, int which, int force)
Eric Snow4e9da0d2018-02-02 21:49:49 -0700688{
Eric Snow3ab01362018-05-17 10:27:09 -0400689 // XXX Handle the ends.
690 // XXX Handle force is True.
691
Eric Snow4e9da0d2018-02-02 21:49:49 -0700692 // Ensure all the "send"-associated interpreters are closed.
693 _channelend *end;
694 for (end = ends->send; end != NULL; end = end->next) {
695 _channelends_close_end(ends, end, 1);
696 }
697
698 // Ensure all the "recv"-associated interpreters are closed.
699 for (end = ends->recv; end != NULL; end = end->next) {
700 _channelends_close_end(ends, end, 0);
701 }
702}
703
704/* channels */
705
706struct _channel;
Eric Snow3ab01362018-05-17 10:27:09 -0400707struct _channel_closing;
708static void _channel_clear_closing(struct _channel *);
709static void _channel_finish_closing(struct _channel *);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700710
711typedef struct _channel {
712 PyThread_type_lock mutex;
713 _channelqueue *queue;
714 _channelends *ends;
715 int open;
Eric Snow3ab01362018-05-17 10:27:09 -0400716 struct _channel_closing *closing;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700717} _PyChannelState;
718
719static _PyChannelState *
720_channel_new(void)
721{
722 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
723 if (chan == NULL) {
724 return NULL;
725 }
726 chan->mutex = PyThread_allocate_lock();
727 if (chan->mutex == NULL) {
728 PyMem_Free(chan);
729 PyErr_SetString(ChannelError,
730 "can't initialize mutex for new channel");
731 return NULL;
732 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700733 chan->queue = _channelqueue_new();
734 if (chan->queue == NULL) {
735 PyMem_Free(chan);
736 return NULL;
737 }
738 chan->ends = _channelends_new();
739 if (chan->ends == NULL) {
740 _channelqueue_free(chan->queue);
741 PyMem_Free(chan);
742 return NULL;
743 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700744 chan->open = 1;
Eric Snow3ab01362018-05-17 10:27:09 -0400745 chan->closing = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700746 return chan;
747}
748
Eric Snow4e9da0d2018-02-02 21:49:49 -0700749static void
750_channel_free(_PyChannelState *chan)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700751{
Eric Snow3ab01362018-05-17 10:27:09 -0400752 _channel_clear_closing(chan);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700753 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
754 _channelqueue_free(chan->queue);
755 _channelends_free(chan->ends);
756 PyThread_release_lock(chan->mutex);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700757
Eric Snow4e9da0d2018-02-02 21:49:49 -0700758 PyThread_free_lock(chan->mutex);
759 PyMem_Free(chan);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700760}
761
Eric Snow4e9da0d2018-02-02 21:49:49 -0700762static int
763_channel_add(_PyChannelState *chan, int64_t interp,
764 _PyCrossInterpreterData *data)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700765{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700766 int res = -1;
767 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
768
Eric Snow7f8bfc92018-01-29 18:23:44 -0700769 if (!chan->open) {
770 PyErr_SetString(ChannelClosedError, "channel closed");
Eric Snow4e9da0d2018-02-02 21:49:49 -0700771 goto done;
772 }
773 if (_channelends_associate(chan->ends, interp, 1) != 0) {
774 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700775 }
776
Eric Snow4e9da0d2018-02-02 21:49:49 -0700777 if (_channelqueue_put(chan->queue, data) != 0) {
778 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700779 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700780
781 res = 0;
782done:
783 PyThread_release_lock(chan->mutex);
784 return res;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700785}
786
Eric Snow4e9da0d2018-02-02 21:49:49 -0700787static _PyCrossInterpreterData *
788_channel_next(_PyChannelState *chan, int64_t interp)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700789{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700790 _PyCrossInterpreterData *data = NULL;
791 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
792
793 if (!chan->open) {
794 PyErr_SetString(ChannelClosedError, "channel closed");
795 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700796 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700797 if (_channelends_associate(chan->ends, interp, 0) != 0) {
798 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700799 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700800
801 data = _channelqueue_get(chan->queue);
Eric Snow3ab01362018-05-17 10:27:09 -0400802 if (data == NULL && !PyErr_Occurred() && chan->closing != NULL) {
803 chan->open = 0;
804 }
805
Eric Snow4e9da0d2018-02-02 21:49:49 -0700806done:
807 PyThread_release_lock(chan->mutex);
Eric Snow3ab01362018-05-17 10:27:09 -0400808 if (chan->queue->count == 0) {
809 _channel_finish_closing(chan);
810 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700811 return data;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700812}
813
814static int
Eric Snow3ab01362018-05-17 10:27:09 -0400815_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700816{
817 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
818
819 int res = -1;
820 if (!chan->open) {
821 PyErr_SetString(ChannelClosedError, "channel already closed");
822 goto done;
823 }
824
Eric Snow3ab01362018-05-17 10:27:09 -0400825 if (_channelends_close_interpreter(chan->ends, interp, end) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700826 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700827 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700828 chan->open = _channelends_is_open(chan->ends);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700829
830 res = 0;
831done:
832 PyThread_release_lock(chan->mutex);
833 return res;
834}
835
836static int
Eric Snow3ab01362018-05-17 10:27:09 -0400837_channel_close_all(_PyChannelState *chan, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700838{
839 int res = -1;
840 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
841
842 if (!chan->open) {
843 PyErr_SetString(ChannelClosedError, "channel already closed");
844 goto done;
845 }
846
Eric Snow3ab01362018-05-17 10:27:09 -0400847 if (!force && chan->queue->count > 0) {
848 PyErr_SetString(ChannelNotEmptyError,
849 "may not be closed if not empty (try force=True)");
850 goto done;
851 }
852
Eric Snow7f8bfc92018-01-29 18:23:44 -0700853 chan->open = 0;
854
855 // We *could* also just leave these in place, since we've marked
856 // the channel as closed already.
Eric Snow3ab01362018-05-17 10:27:09 -0400857 _channelends_close_all(chan->ends, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700858
859 res = 0;
860done:
861 PyThread_release_lock(chan->mutex);
862 return res;
863}
864
Eric Snow4e9da0d2018-02-02 21:49:49 -0700865/* the set of channels */
Eric Snow7f8bfc92018-01-29 18:23:44 -0700866
867struct _channelref;
868
869typedef struct _channelref {
870 int64_t id;
871 _PyChannelState *chan;
872 struct _channelref *next;
873 Py_ssize_t objcount;
874} _channelref;
875
876static _channelref *
877_channelref_new(int64_t id, _PyChannelState *chan)
878{
879 _channelref *ref = PyMem_NEW(_channelref, 1);
880 if (ref == NULL) {
881 return NULL;
882 }
883 ref->id = id;
884 ref->chan = chan;
885 ref->next = NULL;
886 ref->objcount = 0;
887 return ref;
888}
889
Eric Snow4e9da0d2018-02-02 21:49:49 -0700890//static void
891//_channelref_clear(_channelref *ref)
892//{
893// ref->id = -1;
894// ref->chan = NULL;
895// ref->next = NULL;
896// ref->objcount = 0;
897//}
898
899static void
900_channelref_free(_channelref *ref)
901{
Eric Snow3ab01362018-05-17 10:27:09 -0400902 if (ref->chan != NULL) {
903 _channel_clear_closing(ref->chan);
904 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700905 //_channelref_clear(ref);
906 PyMem_Free(ref);
907}
908
Eric Snow7f8bfc92018-01-29 18:23:44 -0700909static _channelref *
910_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
911{
912 _channelref *prev = NULL;
913 _channelref *ref = first;
914 while (ref != NULL) {
915 if (ref->id == id) {
916 break;
917 }
918 prev = ref;
919 ref = ref->next;
920 }
921 if (pprev != NULL) {
922 *pprev = prev;
923 }
924 return ref;
925}
926
927typedef struct _channels {
928 PyThread_type_lock mutex;
929 _channelref *head;
930 int64_t numopen;
931 int64_t next_id;
932} _channels;
933
934static int
935_channels_init(_channels *channels)
936{
937 if (channels->mutex == NULL) {
938 channels->mutex = PyThread_allocate_lock();
939 if (channels->mutex == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700940 PyErr_SetString(ChannelError,
941 "can't initialize mutex for channel management");
942 return -1;
943 }
944 }
945 channels->head = NULL;
946 channels->numopen = 0;
947 channels->next_id = 0;
948 return 0;
949}
950
951static int64_t
952_channels_next_id(_channels *channels) // needs lock
953{
954 int64_t id = channels->next_id;
955 if (id < 0) {
956 /* overflow */
957 PyErr_SetString(ChannelError,
958 "failed to get a channel ID");
959 return -1;
960 }
961 channels->next_id += 1;
962 return id;
963}
964
965static _PyChannelState *
966_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
967{
968 _PyChannelState *chan = NULL;
969 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
970 if (pmutex != NULL) {
971 *pmutex = NULL;
972 }
973
974 _channelref *ref = _channelref_find(channels->head, id, NULL);
975 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -0600976 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700977 goto done;
978 }
979 if (ref->chan == NULL || !ref->chan->open) {
Eric Snowab4a1982018-06-13 08:02:39 -0600980 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700981 goto done;
982 }
983
984 if (pmutex != NULL) {
985 // The mutex will be closed by the caller.
986 *pmutex = channels->mutex;
987 }
988
989 chan = ref->chan;
990done:
991 if (pmutex == NULL || *pmutex == NULL) {
992 PyThread_release_lock(channels->mutex);
993 }
994 return chan;
995}
996
997static int64_t
998_channels_add(_channels *channels, _PyChannelState *chan)
999{
1000 int64_t cid = -1;
1001 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1002
1003 // Create a new ref.
1004 int64_t id = _channels_next_id(channels);
1005 if (id < 0) {
1006 goto done;
1007 }
1008 _channelref *ref = _channelref_new(id, chan);
1009 if (ref == NULL) {
1010 goto done;
1011 }
1012
1013 // Add it to the list.
1014 // We assume that the channel is a new one (not already in the list).
1015 ref->next = channels->head;
1016 channels->head = ref;
1017 channels->numopen += 1;
1018
1019 cid = id;
1020done:
1021 PyThread_release_lock(channels->mutex);
1022 return cid;
1023}
1024
Eric Snow3ab01362018-05-17 10:27:09 -04001025/* forward */
1026static int _channel_set_closing(struct _channelref *, PyThread_type_lock);
1027
Eric Snow7f8bfc92018-01-29 18:23:44 -07001028static int
Eric Snow3ab01362018-05-17 10:27:09 -04001029_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan,
1030 int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001031{
1032 int res = -1;
1033 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1034 if (pchan != NULL) {
1035 *pchan = NULL;
1036 }
1037
1038 _channelref *ref = _channelref_find(channels->head, cid, NULL);
1039 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001040 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001041 goto done;
1042 }
1043
1044 if (ref->chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001045 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001046 goto done;
1047 }
Eric Snow3ab01362018-05-17 10:27:09 -04001048 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001049 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001050 goto done;
1051 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001052 else {
Eric Snow3ab01362018-05-17 10:27:09 -04001053 if (_channel_close_all(ref->chan, end, force) != 0) {
1054 if (end == CHANNEL_SEND &&
1055 PyErr_ExceptionMatches(ChannelNotEmptyError)) {
1056 if (ref->chan->closing != NULL) {
Eric Snow6854e802018-06-01 16:26:01 -06001057 PyErr_Format(ChannelClosedError,
Eric Snowab4a1982018-06-13 08:02:39 -06001058 "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001059 goto done;
1060 }
1061 // Mark the channel as closing and return. The channel
1062 // will be cleaned up in _channel_next().
1063 PyErr_Clear();
1064 if (_channel_set_closing(ref, channels->mutex) != 0) {
1065 goto done;
1066 }
1067 if (pchan != NULL) {
1068 *pchan = ref->chan;
1069 }
1070 res = 0;
1071 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001072 goto done;
1073 }
1074 if (pchan != NULL) {
1075 *pchan = ref->chan;
1076 }
Eric Snow3ab01362018-05-17 10:27:09 -04001077 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001078 _channel_free(ref->chan);
1079 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001080 ref->chan = NULL;
1081 }
1082
1083 res = 0;
1084done:
1085 PyThread_release_lock(channels->mutex);
1086 return res;
1087}
1088
1089static void
1090_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1091 _PyChannelState **pchan)
1092{
1093 if (ref == channels->head) {
1094 channels->head = ref->next;
1095 }
1096 else {
1097 prev->next = ref->next;
1098 }
1099 channels->numopen -= 1;
1100
1101 if (pchan != NULL) {
1102 *pchan = ref->chan;
1103 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001104 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001105}
1106
1107static int
1108_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1109{
1110 int res = -1;
1111 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1112
1113 if (pchan != NULL) {
1114 *pchan = NULL;
1115 }
1116
1117 _channelref *prev = NULL;
1118 _channelref *ref = _channelref_find(channels->head, id, &prev);
1119 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001120 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001121 goto done;
1122 }
1123
1124 _channels_remove_ref(channels, ref, prev, pchan);
1125
1126 res = 0;
1127done:
1128 PyThread_release_lock(channels->mutex);
1129 return res;
1130}
1131
1132static int
1133_channels_add_id_object(_channels *channels, int64_t id)
1134{
1135 int res = -1;
1136 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1137
1138 _channelref *ref = _channelref_find(channels->head, id, NULL);
1139 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001140 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001141 goto done;
1142 }
1143 ref->objcount += 1;
1144
1145 res = 0;
1146done:
1147 PyThread_release_lock(channels->mutex);
1148 return res;
1149}
1150
1151static void
1152_channels_drop_id_object(_channels *channels, int64_t id)
1153{
1154 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1155
1156 _channelref *prev = NULL;
1157 _channelref *ref = _channelref_find(channels->head, id, &prev);
1158 if (ref == NULL) {
1159 // Already destroyed.
1160 goto done;
1161 }
1162 ref->objcount -= 1;
1163
1164 // Destroy if no longer used.
1165 if (ref->objcount == 0) {
1166 _PyChannelState *chan = NULL;
1167 _channels_remove_ref(channels, ref, prev, &chan);
1168 if (chan != NULL) {
1169 _channel_free(chan);
1170 }
1171 }
1172
1173done:
1174 PyThread_release_lock(channels->mutex);
1175}
1176
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001177static int64_t *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001178_channels_list_all(_channels *channels, int64_t *count)
1179{
1180 int64_t *cids = NULL;
1181 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1182 int64_t numopen = channels->numopen;
1183 if (numopen >= PY_SSIZE_T_MAX) {
1184 PyErr_SetString(PyExc_RuntimeError, "too many channels open");
1185 goto done;
1186 }
1187 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
1188 if (ids == NULL) {
1189 goto done;
1190 }
1191 _channelref *ref = channels->head;
1192 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
1193 ids[i] = ref->id;
1194 }
1195 *count = channels->numopen;
1196
1197 cids = ids;
1198done:
1199 PyThread_release_lock(channels->mutex);
1200 return cids;
1201}
1202
Eric Snow3ab01362018-05-17 10:27:09 -04001203/* support for closing non-empty channels */
1204
1205struct _channel_closing {
1206 struct _channelref *ref;
1207};
1208
1209static int
1210_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
1211 struct _channel *chan = ref->chan;
1212 if (chan == NULL) {
1213 // already closed
1214 return 0;
1215 }
1216 int res = -1;
1217 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1218 if (chan->closing != NULL) {
1219 PyErr_SetString(ChannelClosedError, "channel closed");
1220 goto done;
1221 }
1222 chan->closing = PyMem_NEW(struct _channel_closing, 1);
1223 if (chan->closing == NULL) {
1224 goto done;
1225 }
1226 chan->closing->ref = ref;
1227
1228 res = 0;
1229done:
1230 PyThread_release_lock(chan->mutex);
1231 return res;
1232}
1233
1234static void
1235_channel_clear_closing(struct _channel *chan) {
1236 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1237 if (chan->closing != NULL) {
1238 PyMem_Free(chan->closing);
1239 chan->closing = NULL;
1240 }
1241 PyThread_release_lock(chan->mutex);
1242}
1243
1244static void
1245_channel_finish_closing(struct _channel *chan) {
1246 struct _channel_closing *closing = chan->closing;
1247 if (closing == NULL) {
1248 return;
1249 }
1250 _channelref *ref = closing->ref;
1251 _channel_clear_closing(chan);
1252 // Do the things that would have been done in _channels_close().
1253 ref->chan = NULL;
1254 _channel_free(chan);
Zackery Spytz1a2252e2019-05-06 10:56:51 -06001255}
Eric Snow3ab01362018-05-17 10:27:09 -04001256
Eric Snow7f8bfc92018-01-29 18:23:44 -07001257/* "high"-level channel-related functions */
1258
1259static int64_t
1260_channel_create(_channels *channels)
1261{
1262 _PyChannelState *chan = _channel_new();
1263 if (chan == NULL) {
1264 return -1;
1265 }
1266 int64_t id = _channels_add(channels, chan);
1267 if (id < 0) {
1268 _channel_free(chan);
1269 return -1;
1270 }
1271 return id;
1272}
1273
1274static int
1275_channel_destroy(_channels *channels, int64_t id)
1276{
1277 _PyChannelState *chan = NULL;
1278 if (_channels_remove(channels, id, &chan) != 0) {
1279 return -1;
1280 }
1281 if (chan != NULL) {
1282 _channel_free(chan);
1283 }
1284 return 0;
1285}
1286
1287static int
1288_channel_send(_channels *channels, int64_t id, PyObject *obj)
1289{
1290 PyInterpreterState *interp = _get_current();
1291 if (interp == NULL) {
1292 return -1;
1293 }
1294
1295 // Look up the channel.
1296 PyThread_type_lock mutex = NULL;
1297 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1298 if (chan == NULL) {
1299 return -1;
1300 }
1301 // Past this point we are responsible for releasing the mutex.
1302
Eric Snow3ab01362018-05-17 10:27:09 -04001303 if (chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001304 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow3ab01362018-05-17 10:27:09 -04001305 PyThread_release_lock(mutex);
1306 return -1;
1307 }
1308
Eric Snow7f8bfc92018-01-29 18:23:44 -07001309 // Convert the object to cross-interpreter data.
1310 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
1311 if (data == NULL) {
1312 PyThread_release_lock(mutex);
1313 return -1;
1314 }
1315 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
Victor Stinner4d61e6e2019-03-04 14:21:28 +01001316 PyThread_release_lock(mutex);
Eric Snowc11183c2019-03-15 16:35:46 -06001317 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001318 return -1;
1319 }
1320
1321 // Add the data to the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06001322 int res = _channel_add(chan, PyInterpreterState_GetID(interp), data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001323 PyThread_release_lock(mutex);
1324 if (res != 0) {
1325 _PyCrossInterpreterData_Release(data);
1326 PyMem_Free(data);
1327 return -1;
1328 }
1329
1330 return 0;
1331}
1332
1333static PyObject *
1334_channel_recv(_channels *channels, int64_t id)
1335{
1336 PyInterpreterState *interp = _get_current();
1337 if (interp == NULL) {
1338 return NULL;
1339 }
1340
1341 // Look up the channel.
1342 PyThread_type_lock mutex = NULL;
1343 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1344 if (chan == NULL) {
1345 return NULL;
1346 }
1347 // Past this point we are responsible for releasing the mutex.
1348
1349 // Pop off the next item from the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06001350 _PyCrossInterpreterData *data = _channel_next(chan, PyInterpreterState_GetID(interp));
Eric Snow7f8bfc92018-01-29 18:23:44 -07001351 PyThread_release_lock(mutex);
1352 if (data == NULL) {
Eric Snow6d2cd902018-05-16 15:04:57 -04001353 if (!PyErr_Occurred()) {
Eric Snowab4a1982018-06-13 08:02:39 -06001354 PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001355 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001356 return NULL;
1357 }
1358
1359 // Convert the data back to an object.
1360 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
1361 if (obj == NULL) {
1362 return NULL;
1363 }
1364 _PyCrossInterpreterData_Release(data);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001365 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001366
1367 return obj;
1368}
1369
1370static int
1371_channel_drop(_channels *channels, int64_t id, int send, int recv)
1372{
1373 PyInterpreterState *interp = _get_current();
1374 if (interp == NULL) {
1375 return -1;
1376 }
1377
1378 // Look up the channel.
1379 PyThread_type_lock mutex = NULL;
1380 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1381 if (chan == NULL) {
1382 return -1;
1383 }
1384 // Past this point we are responsible for releasing the mutex.
1385
1386 // Close one or both of the two ends.
Eric Snowc11183c2019-03-15 16:35:46 -06001387 int res = _channel_close_interpreter(chan, PyInterpreterState_GetID(interp), send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001388 PyThread_release_lock(mutex);
1389 return res;
1390}
1391
1392static int
Eric Snow3ab01362018-05-17 10:27:09 -04001393_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001394{
Eric Snow3ab01362018-05-17 10:27:09 -04001395 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001396}
1397
1398/* ChannelID class */
1399
Eric Snow7f8bfc92018-01-29 18:23:44 -07001400static PyTypeObject ChannelIDtype;
1401
1402typedef struct channelid {
1403 PyObject_HEAD
1404 int64_t id;
1405 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001406 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001407 _channels *channels;
1408} channelid;
1409
Serhiy Storchakabf169912019-09-13 22:50:27 +03001410static int
1411channel_id_converter(PyObject *arg, void *ptr)
1412{
1413 int64_t cid;
1414 if (PyObject_TypeCheck(arg, &ChannelIDtype)) {
1415 cid = ((channelid *)arg)->id;
1416 }
1417 else if (PyIndex_Check(arg)) {
1418 cid = PyLong_AsLongLong(arg);
1419 if (cid == -1 && PyErr_Occurred()) {
1420 return 0;
1421 }
1422 if (cid < 0) {
1423 PyErr_Format(PyExc_ValueError,
1424 "channel ID must be a non-negative int, got %R", arg);
1425 return 0;
1426 }
1427 }
1428 else {
1429 PyErr_Format(PyExc_TypeError,
1430 "channel ID must be an int, got %.100s",
1431 arg->ob_type->tp_name);
1432 return 0;
1433 }
1434 *(int64_t *)ptr = cid;
1435 return 1;
1436}
1437
Eric Snow7f8bfc92018-01-29 18:23:44 -07001438static channelid *
1439newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001440 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001441{
1442 channelid *self = PyObject_New(channelid, cls);
1443 if (self == NULL) {
1444 return NULL;
1445 }
1446 self->id = cid;
1447 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001448 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001449 self->channels = channels;
1450
1451 if (_channels_add_id_object(channels, cid) != 0) {
1452 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1453 PyErr_Clear();
1454 }
1455 else {
1456 Py_DECREF((PyObject *)self);
1457 return NULL;
1458 }
1459 }
1460
1461 return self;
1462}
1463
1464static _channels * _global_channels(void);
1465
1466static PyObject *
1467channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1468{
Eric Snow6d2cd902018-05-16 15:04:57 -04001469 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03001470 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001471 int send = -1;
1472 int recv = -1;
1473 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001474 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001475 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03001476 "O&|$pppp:ChannelID.__new__", kwlist,
1477 channel_id_converter, &cid, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001478 return NULL;
1479
Eric Snow7f8bfc92018-01-29 18:23:44 -07001480 // Handle "send" and "recv".
1481 if (send == 0 && recv == 0) {
1482 PyErr_SetString(PyExc_ValueError,
1483 "'send' and 'recv' cannot both be False");
1484 return NULL;
1485 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001486
Eric Snow7f8bfc92018-01-29 18:23:44 -07001487 int end = 0;
1488 if (send == 1) {
1489 if (recv == 0 || recv == -1) {
1490 end = CHANNEL_SEND;
1491 }
1492 }
1493 else if (recv == 1) {
1494 end = CHANNEL_RECV;
1495 }
1496
Eric Snow6d2cd902018-05-16 15:04:57 -04001497 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
1498 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001499}
1500
1501static void
1502channelid_dealloc(PyObject *v)
1503{
1504 int64_t cid = ((channelid *)v)->id;
1505 _channels *channels = ((channelid *)v)->channels;
1506 Py_TYPE(v)->tp_free(v);
1507
1508 _channels_drop_id_object(channels, cid);
1509}
1510
1511static PyObject *
1512channelid_repr(PyObject *self)
1513{
1514 PyTypeObject *type = Py_TYPE(self);
1515 const char *name = _PyType_Name(type);
1516
1517 channelid *cid = (channelid *)self;
1518 const char *fmt;
1519 if (cid->end == CHANNEL_SEND) {
Eric Snowab4a1982018-06-13 08:02:39 -06001520 fmt = "%s(%" PRId64 ", send=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001521 }
1522 else if (cid->end == CHANNEL_RECV) {
Eric Snowab4a1982018-06-13 08:02:39 -06001523 fmt = "%s(%" PRId64 ", recv=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001524 }
1525 else {
Eric Snowab4a1982018-06-13 08:02:39 -06001526 fmt = "%s(%" PRId64 ")";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001527 }
1528 return PyUnicode_FromFormat(fmt, name, cid->id);
1529}
1530
Eric Snow6d2cd902018-05-16 15:04:57 -04001531static PyObject *
1532channelid_str(PyObject *self)
1533{
1534 channelid *cid = (channelid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06001535 return PyUnicode_FromFormat("%" PRId64 "", cid->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001536}
1537
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001538static PyObject *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001539channelid_int(PyObject *self)
1540{
1541 channelid *cid = (channelid *)self;
1542 return PyLong_FromLongLong(cid->id);
1543}
1544
1545static PyNumberMethods channelid_as_number = {
1546 0, /* nb_add */
1547 0, /* nb_subtract */
1548 0, /* nb_multiply */
1549 0, /* nb_remainder */
1550 0, /* nb_divmod */
1551 0, /* nb_power */
1552 0, /* nb_negative */
1553 0, /* nb_positive */
1554 0, /* nb_absolute */
1555 0, /* nb_bool */
1556 0, /* nb_invert */
1557 0, /* nb_lshift */
1558 0, /* nb_rshift */
1559 0, /* nb_and */
1560 0, /* nb_xor */
1561 0, /* nb_or */
1562 (unaryfunc)channelid_int, /* nb_int */
1563 0, /* nb_reserved */
1564 0, /* nb_float */
1565
1566 0, /* nb_inplace_add */
1567 0, /* nb_inplace_subtract */
1568 0, /* nb_inplace_multiply */
1569 0, /* nb_inplace_remainder */
1570 0, /* nb_inplace_power */
1571 0, /* nb_inplace_lshift */
1572 0, /* nb_inplace_rshift */
1573 0, /* nb_inplace_and */
1574 0, /* nb_inplace_xor */
1575 0, /* nb_inplace_or */
1576
1577 0, /* nb_floor_divide */
1578 0, /* nb_true_divide */
1579 0, /* nb_inplace_floor_divide */
1580 0, /* nb_inplace_true_divide */
1581
1582 (unaryfunc)channelid_int, /* nb_index */
1583};
1584
1585static Py_hash_t
1586channelid_hash(PyObject *self)
1587{
1588 channelid *cid = (channelid *)self;
1589 PyObject *id = PyLong_FromLongLong(cid->id);
1590 if (id == NULL) {
1591 return -1;
1592 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001593 Py_hash_t hash = PyObject_Hash(id);
1594 Py_DECREF(id);
1595 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001596}
1597
1598static PyObject *
1599channelid_richcompare(PyObject *self, PyObject *other, int op)
1600{
1601 if (op != Py_EQ && op != Py_NE) {
1602 Py_RETURN_NOTIMPLEMENTED;
1603 }
1604
1605 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1606 Py_RETURN_NOTIMPLEMENTED;
1607 }
1608
1609 channelid *cid = (channelid *)self;
1610 int equal;
1611 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1612 channelid *othercid = (channelid *)other;
Serhiy Storchakabf169912019-09-13 22:50:27 +03001613 equal = (cid->end == othercid->end) && (cid->id == othercid->id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001614 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001615 else if (PyLong_Check(other)) {
1616 /* Fast path */
1617 int overflow;
1618 long long othercid = PyLong_AsLongLongAndOverflow(other, &overflow);
1619 if (othercid == -1 && PyErr_Occurred()) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001620 return NULL;
1621 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001622 equal = !overflow && (othercid >= 0) && (cid->id == othercid);
1623 }
1624 else if (PyNumber_Check(other)) {
1625 PyObject *pyid = PyLong_FromLongLong(cid->id);
1626 if (pyid == NULL) {
1627 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001628 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001629 PyObject *res = PyObject_RichCompare(pyid, other, op);
1630 Py_DECREF(pyid);
1631 return res;
1632 }
1633 else {
1634 Py_RETURN_NOTIMPLEMENTED;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001635 }
1636
1637 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1638 Py_RETURN_TRUE;
1639 }
1640 Py_RETURN_FALSE;
1641}
1642
Eric Snowab4a1982018-06-13 08:02:39 -06001643static PyObject *
1644_channel_from_cid(PyObject *cid, int end)
1645{
1646 PyObject *highlevel = PyImport_ImportModule("interpreters");
1647 if (highlevel == NULL) {
1648 PyErr_Clear();
1649 highlevel = PyImport_ImportModule("test.support.interpreters");
1650 if (highlevel == NULL) {
1651 return NULL;
1652 }
1653 }
1654 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
1655 "SendChannel";
1656 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1657 Py_DECREF(highlevel);
1658 if (cls == NULL) {
1659 return NULL;
1660 }
1661 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1662 Py_DECREF(cls);
1663 if (chan == NULL) {
1664 return NULL;
1665 }
1666 return chan;
1667}
1668
Eric Snow7f8bfc92018-01-29 18:23:44 -07001669struct _channelid_xid {
1670 int64_t id;
1671 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001672 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001673};
1674
1675static PyObject *
1676_channelid_from_xid(_PyCrossInterpreterData *data)
1677{
1678 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001679 // Note that we do not preserve the "resolve" flag.
1680 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1681 _global_channels(), 0, 0);
1682 if (xid->end == 0) {
1683 return cid;
1684 }
1685 if (!xid->resolve) {
1686 return cid;
1687 }
1688
1689 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06001690 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04001691 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001692 PyErr_Clear();
1693 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04001694 }
1695 Py_DECREF(cid);
1696 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001697}
1698
1699static int
1700_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1701{
1702 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1703 if (xid == NULL) {
1704 return -1;
1705 }
1706 xid->id = ((channelid *)obj)->id;
1707 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001708 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001709
1710 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06001711 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001712 data->obj = obj;
1713 data->new_object = _channelid_from_xid;
1714 data->free = PyMem_Free;
1715 return 0;
1716}
1717
1718static PyObject *
1719channelid_end(PyObject *self, void *end)
1720{
1721 int force = 1;
1722 channelid *cid = (channelid *)self;
1723 if (end != NULL) {
1724 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001725 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001726 }
1727
1728 if (cid->end == CHANNEL_SEND) {
1729 return PyUnicode_InternFromString("send");
1730 }
1731 if (cid->end == CHANNEL_RECV) {
1732 return PyUnicode_InternFromString("recv");
1733 }
1734 return PyUnicode_InternFromString("both");
1735}
1736
1737static int _channelid_end_send = CHANNEL_SEND;
1738static int _channelid_end_recv = CHANNEL_RECV;
1739
1740static PyGetSetDef channelid_getsets[] = {
1741 {"end", (getter)channelid_end, NULL,
1742 PyDoc_STR("'send', 'recv', or 'both'")},
1743 {"send", (getter)channelid_end, NULL,
1744 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1745 {"recv", (getter)channelid_end, NULL,
1746 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1747 {NULL}
1748};
1749
1750PyDoc_STRVAR(channelid_doc,
1751"A channel ID identifies a channel and may be used as an int.");
1752
1753static PyTypeObject ChannelIDtype = {
1754 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1755 "_xxsubinterpreters.ChannelID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02001756 sizeof(channelid), /* tp_basicsize */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001757 0, /* tp_itemsize */
1758 (destructor)channelid_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001759 0, /* tp_vectorcall_offset */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001760 0, /* tp_getattr */
1761 0, /* tp_setattr */
1762 0, /* tp_as_async */
1763 (reprfunc)channelid_repr, /* tp_repr */
1764 &channelid_as_number, /* tp_as_number */
1765 0, /* tp_as_sequence */
1766 0, /* tp_as_mapping */
1767 channelid_hash, /* tp_hash */
1768 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001769 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001770 0, /* tp_getattro */
1771 0, /* tp_setattro */
1772 0, /* tp_as_buffer */
Serhiy Storchakabf169912019-09-13 22:50:27 +03001773 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001774 channelid_doc, /* tp_doc */
1775 0, /* tp_traverse */
1776 0, /* tp_clear */
1777 channelid_richcompare, /* tp_richcompare */
1778 0, /* tp_weaklistoffset */
1779 0, /* tp_iter */
1780 0, /* tp_iternext */
1781 0, /* tp_methods */
1782 0, /* tp_members */
1783 channelid_getsets, /* tp_getset */
1784 0, /* tp_base */
1785 0, /* tp_dict */
1786 0, /* tp_descr_get */
1787 0, /* tp_descr_set */
1788 0, /* tp_dictoffset */
1789 0, /* tp_init */
1790 0, /* tp_alloc */
1791 // Note that we do not set tp_new to channelid_new. Instead we
1792 // set it to NULL, meaning it cannot be instantiated from Python
1793 // code. We do this because there is a strong relationship between
1794 // channel IDs and the channel lifecycle, so this limitation avoids
1795 // related complications.
1796 NULL, /* tp_new */
1797};
1798
Eric Snow4e9da0d2018-02-02 21:49:49 -07001799
1800/* interpreter-specific code ************************************************/
1801
1802static PyObject * RunFailedError = NULL;
1803
1804static int
1805interp_exceptions_init(PyObject *ns)
1806{
1807 // XXX Move the exceptions into per-module memory?
1808
1809 if (RunFailedError == NULL) {
1810 // An uncaught exception came out of interp_run_string().
1811 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1812 PyExc_RuntimeError, NULL);
1813 if (RunFailedError == NULL) {
1814 return -1;
1815 }
1816 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1817 return -1;
1818 }
1819 }
1820
1821 return 0;
1822}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001823
Eric Snow7f8bfc92018-01-29 18:23:44 -07001824static int
1825_is_running(PyInterpreterState *interp)
1826{
1827 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1828 if (PyThreadState_Next(tstate) != NULL) {
1829 PyErr_SetString(PyExc_RuntimeError,
1830 "interpreter has more than one thread");
1831 return -1;
1832 }
1833 PyFrameObject *frame = tstate->frame;
1834 if (frame == NULL) {
1835 if (PyErr_Occurred() != NULL) {
1836 return -1;
1837 }
1838 return 0;
1839 }
1840 return (int)(frame->f_executing);
1841}
1842
1843static int
1844_ensure_not_running(PyInterpreterState *interp)
1845{
1846 int is_running = _is_running(interp);
1847 if (is_running < 0) {
1848 return -1;
1849 }
1850 if (is_running) {
1851 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1852 return -1;
1853 }
1854 return 0;
1855}
1856
1857static int
1858_run_script(PyInterpreterState *interp, const char *codestr,
Eric Snow4e9da0d2018-02-02 21:49:49 -07001859 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001860{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001861 PyObject *exctype = NULL;
1862 PyObject *excval = NULL;
1863 PyObject *tb = NULL;
1864
Eric Snowc11183c2019-03-15 16:35:46 -06001865 PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001866 if (main_mod == NULL) {
1867 goto error;
1868 }
1869 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1870 Py_DECREF(main_mod);
1871 if (ns == NULL) {
1872 goto error;
1873 }
1874 Py_INCREF(ns);
1875
1876 // Apply the cross-interpreter data.
1877 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001878 if (_sharedns_apply(shared, ns) != 0) {
1879 Py_DECREF(ns);
1880 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001881 }
1882 }
1883
1884 // Run the string (see PyRun_SimpleStringFlags).
1885 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1886 Py_DECREF(ns);
1887 if (result == NULL) {
1888 goto error;
1889 }
1890 else {
1891 Py_DECREF(result); // We throw away the result.
1892 }
1893
Eric Snow4e9da0d2018-02-02 21:49:49 -07001894 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001895 return 0;
1896
1897error:
Eric Snow4e9da0d2018-02-02 21:49:49 -07001898 PyErr_Fetch(&exctype, &excval, &tb);
1899
1900 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1901 Py_XDECREF(exctype);
1902 Py_XDECREF(excval);
1903 Py_XDECREF(tb);
1904 if (sharedexc == NULL) {
1905 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1906 PyErr_Clear();
1907 sharedexc = NULL;
1908 }
1909 else {
1910 assert(!PyErr_Occurred());
1911 }
1912 *exc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001913 return -1;
1914}
1915
1916static int
1917_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1918 PyObject *shareables)
1919{
1920 if (_ensure_not_running(interp) < 0) {
1921 return -1;
1922 }
1923
Eric Snow4e9da0d2018-02-02 21:49:49 -07001924 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001925 if (shared == NULL && PyErr_Occurred()) {
1926 return -1;
1927 }
1928
1929 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001930 PyThreadState *save_tstate = NULL;
Victor Stinnercaba55b2018-08-03 15:33:52 +02001931 if (interp != _PyInterpreterState_Get()) {
Eric Snowf53d9f22018-02-20 16:30:17 -07001932 // XXX Using the "head" thread isn't strictly correct.
1933 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1934 // XXX Possible GILState issues?
1935 save_tstate = PyThreadState_Swap(tstate);
1936 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001937
1938 // Run the script.
1939 _sharedexception *exc = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001940 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001941
1942 // Switch back.
1943 if (save_tstate != NULL) {
1944 PyThreadState_Swap(save_tstate);
1945 }
1946
1947 // Propagate any exception out to the caller.
1948 if (exc != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001949 _sharedexception_apply(exc, RunFailedError);
1950 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001951 }
1952 else if (result != 0) {
1953 // We were unable to allocate a shared exception.
1954 PyErr_NoMemory();
1955 }
1956
1957 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001958 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001959 }
1960
1961 return result;
1962}
1963
1964
1965/* module level code ********************************************************/
1966
1967/* globals is the process-global state for the module. It holds all
1968 the data that we need to share between interpreters, so it cannot
1969 hold PyObject values. */
1970static struct globals {
1971 _channels channels;
1972} _globals = {{0}};
1973
1974static int
1975_init_globals(void)
1976{
1977 if (_channels_init(&_globals.channels) != 0) {
1978 return -1;
1979 }
1980 return 0;
1981}
1982
1983static _channels *
1984_global_channels(void) {
1985 return &_globals.channels;
1986}
1987
1988static PyObject *
1989interp_create(PyObject *self, PyObject *args)
1990{
1991 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
1992 return NULL;
1993 }
1994
1995 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001996 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
1997 // XXX Possible GILState issues?
1998 PyThreadState *tstate = Py_NewInterpreter();
Eric Snow7f8bfc92018-01-29 18:23:44 -07001999 PyThreadState_Swap(save_tstate);
2000 if (tstate == NULL) {
2001 /* Since no new thread state was created, there is no exception to
2002 propagate; raise a fresh one after swapping in the old thread
2003 state. */
2004 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2005 return NULL;
2006 }
Eric Snowc11183c2019-03-15 16:35:46 -06002007 PyObject *idobj = _PyInterpreterState_GetIDObject(tstate->interp);
2008 if (idobj == NULL) {
2009 // XXX Possible GILState issues?
2010 save_tstate = PyThreadState_Swap(tstate);
2011 Py_EndInterpreter(tstate);
2012 PyThreadState_Swap(save_tstate);
2013 return NULL;
2014 }
2015 _PyInterpreterState_RequireIDRef(tstate->interp, 1);
2016 return idobj;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002017}
2018
2019PyDoc_STRVAR(create_doc,
2020"create() -> ID\n\
2021\n\
2022Create a new interpreter and return a unique generated ID.");
2023
2024
2025static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002026interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002027{
Eric Snow6d2cd902018-05-16 15:04:57 -04002028 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002029 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002030 // XXX Use "L" for id?
2031 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2032 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002033 return NULL;
2034 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002035
2036 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06002037 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002038 if (interp == NULL) {
2039 return NULL;
2040 }
2041
2042 // Ensure we don't try to destroy the current interpreter.
2043 PyInterpreterState *current = _get_current();
2044 if (current == NULL) {
2045 return NULL;
2046 }
2047 if (interp == current) {
2048 PyErr_SetString(PyExc_RuntimeError,
2049 "cannot destroy the current interpreter");
2050 return NULL;
2051 }
2052
2053 // Ensure the interpreter isn't running.
2054 /* XXX We *could* support destroying a running interpreter but
2055 aren't going to worry about it for now. */
2056 if (_ensure_not_running(interp) < 0) {
2057 return NULL;
2058 }
2059
2060 // Destroy the interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002061 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2062 // XXX Possible GILState issues?
2063 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002064 Py_EndInterpreter(tstate);
2065 PyThreadState_Swap(save_tstate);
2066
2067 Py_RETURN_NONE;
2068}
2069
2070PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002071"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002072\n\
2073Destroy the identified interpreter.\n\
2074\n\
2075Attempting to destroy the current interpreter results in a RuntimeError.\n\
2076So does an unrecognized ID.");
2077
2078
2079static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302080interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002081{
2082 PyObject *ids, *id;
2083 PyInterpreterState *interp;
2084
2085 ids = PyList_New(0);
2086 if (ids == NULL) {
2087 return NULL;
2088 }
2089
2090 interp = PyInterpreterState_Head();
2091 while (interp != NULL) {
Eric Snowc11183c2019-03-15 16:35:46 -06002092 id = _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002093 if (id == NULL) {
2094 Py_DECREF(ids);
2095 return NULL;
2096 }
2097 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002098 int res = PyList_Insert(ids, 0, id);
2099 Py_DECREF(id);
2100 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002101 Py_DECREF(ids);
2102 return NULL;
2103 }
2104
2105 interp = PyInterpreterState_Next(interp);
2106 }
2107
2108 return ids;
2109}
2110
2111PyDoc_STRVAR(list_all_doc,
2112"list_all() -> [ID]\n\
2113\n\
2114Return a list containing the ID of every existing interpreter.");
2115
2116
2117static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302118interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002119{
2120 PyInterpreterState *interp =_get_current();
2121 if (interp == NULL) {
2122 return NULL;
2123 }
Eric Snowc11183c2019-03-15 16:35:46 -06002124 return _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002125}
2126
2127PyDoc_STRVAR(get_current_doc,
2128"get_current() -> ID\n\
2129\n\
2130Return the ID of current interpreter.");
2131
2132
2133static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302134interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002135{
2136 // Currently, 0 is always the main interpreter.
Eric Snow6d2cd902018-05-16 15:04:57 -04002137 PY_INT64_T id = 0;
Eric Snowc11183c2019-03-15 16:35:46 -06002138 return _PyInterpreterID_New(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002139}
2140
2141PyDoc_STRVAR(get_main_doc,
2142"get_main() -> ID\n\
2143\n\
2144Return the ID of main interpreter.");
2145
2146
2147static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002148interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002149{
Eric Snow6d2cd902018-05-16 15:04:57 -04002150 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002151 PyObject *id, *code;
2152 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002153 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2154 "OU|O:run_string", kwlist,
2155 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002156 return NULL;
2157 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002158
2159 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06002160 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002161 if (interp == NULL) {
2162 return NULL;
2163 }
2164
2165 // Extract code.
2166 Py_ssize_t size;
2167 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2168 if (codestr == NULL) {
2169 return NULL;
2170 }
2171 if (strlen(codestr) != (size_t)size) {
2172 PyErr_SetString(PyExc_ValueError,
2173 "source code string cannot contain null bytes");
2174 return NULL;
2175 }
2176
2177 // Run the code in the interpreter.
2178 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2179 return NULL;
2180 }
2181 Py_RETURN_NONE;
2182}
2183
2184PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002185"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002186\n\
2187Execute the provided string in the identified interpreter.\n\
2188\n\
2189See PyRun_SimpleStrings.");
2190
2191
2192static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002193object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002194{
Eric Snow6d2cd902018-05-16 15:04:57 -04002195 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002196 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002197 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2198 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002199 return NULL;
2200 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002201
Eric Snow7f8bfc92018-01-29 18:23:44 -07002202 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2203 Py_RETURN_TRUE;
2204 }
2205 PyErr_Clear();
2206 Py_RETURN_FALSE;
2207}
2208
2209PyDoc_STRVAR(is_shareable_doc,
2210"is_shareable(obj) -> bool\n\
2211\n\
2212Return True if the object's data may be shared between interpreters and\n\
2213False otherwise.");
2214
2215
2216static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002217interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002218{
Eric Snow6d2cd902018-05-16 15:04:57 -04002219 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002220 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002221 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2222 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002223 return NULL;
2224 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002225
Eric Snowc11183c2019-03-15 16:35:46 -06002226 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002227 if (interp == NULL) {
2228 return NULL;
2229 }
2230 int is_running = _is_running(interp);
2231 if (is_running < 0) {
2232 return NULL;
2233 }
2234 if (is_running) {
2235 Py_RETURN_TRUE;
2236 }
2237 Py_RETURN_FALSE;
2238}
2239
2240PyDoc_STRVAR(is_running_doc,
2241"is_running(id) -> bool\n\
2242\n\
2243Return whether or not the identified interpreter is running.");
2244
2245static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302246channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002247{
2248 int64_t cid = _channel_create(&_globals.channels);
2249 if (cid < 0) {
2250 return NULL;
2251 }
2252 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002253 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002254 if (id == NULL) {
2255 if (_channel_destroy(&_globals.channels, cid) != 0) {
2256 // XXX issue a warning?
2257 }
2258 return NULL;
2259 }
2260 assert(((channelid *)id)->channels != NULL);
2261 return id;
2262}
2263
2264PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002265"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002266\n\
2267Create a new cross-interpreter channel and return a unique generated ID.");
2268
2269static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002270channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002271{
Eric Snow6d2cd902018-05-16 15:04:57 -04002272 static char *kwlist[] = {"cid", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002273 int64_t cid;
2274 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_destroy", kwlist,
2275 channel_id_converter, &cid)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002276 return NULL;
2277 }
2278
2279 if (_channel_destroy(&_globals.channels, cid) != 0) {
2280 return NULL;
2281 }
2282 Py_RETURN_NONE;
2283}
2284
2285PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002286"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002287\n\
2288Close and finalize the channel. Afterward attempts to use the channel\n\
2289will behave as though it never existed.");
2290
2291static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302292channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002293{
2294 int64_t count = 0;
2295 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2296 if (cids == NULL) {
2297 if (count == 0) {
2298 return PyList_New(0);
2299 }
2300 return NULL;
2301 }
2302 PyObject *ids = PyList_New((Py_ssize_t)count);
2303 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002304 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002305 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002306 int64_t *cur = cids;
2307 for (int64_t i=0; i < count; cur++, i++) {
2308 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002309 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002310 if (id == NULL) {
2311 Py_DECREF(ids);
2312 ids = NULL;
2313 break;
2314 }
2315 PyList_SET_ITEM(ids, i, id);
2316 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002317
2318finally:
2319 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002320 return ids;
2321}
2322
2323PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002324"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002325\n\
2326Return the list of all IDs for active channels.");
2327
2328static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002329channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002330{
Eric Snow6d2cd902018-05-16 15:04:57 -04002331 static char *kwlist[] = {"cid", "obj", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002332 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002333 PyObject *obj;
Serhiy Storchakabf169912019-09-13 22:50:27 +03002334 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O:channel_send", kwlist,
2335 channel_id_converter, &cid, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002336 return NULL;
2337 }
2338
2339 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2340 return NULL;
2341 }
2342 Py_RETURN_NONE;
2343}
2344
2345PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002346"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002347\n\
2348Add the object's data to the channel's queue.");
2349
2350static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002351channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002352{
Eric Snow6d2cd902018-05-16 15:04:57 -04002353 static char *kwlist[] = {"cid", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002354 int64_t cid;
2355 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_recv", kwlist,
2356 channel_id_converter, &cid)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002357 return NULL;
2358 }
2359
2360 return _channel_recv(&_globals.channels, cid);
2361}
2362
2363PyDoc_STRVAR(channel_recv_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002364"channel_recv(cid) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002365\n\
2366Return a new object from the data at the from of the channel's queue.");
2367
2368static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002369channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002370{
Eric Snow6d2cd902018-05-16 15:04:57 -04002371 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002372 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04002373 int send = 0;
2374 int recv = 0;
2375 int force = 0;
2376 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03002377 "O&|$ppp:channel_close", kwlist,
2378 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002379 return NULL;
2380 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002381
Eric Snow3ab01362018-05-17 10:27:09 -04002382 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002383 return NULL;
2384 }
2385 Py_RETURN_NONE;
2386}
2387
2388PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002389"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002390\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002391Close the channel for all interpreters.\n\
2392\n\
2393If the channel is empty then the keyword args are ignored and both\n\
2394ends are immediately closed. Otherwise, if 'force' is True then\n\
2395all queued items are released and both ends are immediately\n\
2396closed.\n\
2397\n\
2398If the channel is not empty *and* 'force' is False then following\n\
2399happens:\n\
2400\n\
2401 * recv is True (regardless of send):\n\
2402 - raise ChannelNotEmptyError\n\
2403 * recv is None and send is None:\n\
2404 - raise ChannelNotEmptyError\n\
2405 * send is True and recv is not True:\n\
2406 - fully close the 'send' end\n\
2407 - close the 'recv' end to interpreters not already receiving\n\
2408 - fully close it once empty\n\
2409\n\
2410Closing an already closed channel results in a ChannelClosedError.\n\
2411\n\
2412Once the channel's ID has no more ref counts in any interpreter\n\
2413the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002414
2415static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002416channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002417{
2418 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002419 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002420 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04002421 int send = 0;
2422 int recv = 0;
2423 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002424 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03002425 "O&|$ppp:channel_release", kwlist,
2426 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002427 return NULL;
2428 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002429 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002430 send = 1;
2431 recv = 1;
2432 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002433
2434 // XXX Handle force is True.
2435 // XXX Fix implicit release.
2436
Eric Snow7f8bfc92018-01-29 18:23:44 -07002437 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2438 return NULL;
2439 }
2440 Py_RETURN_NONE;
2441}
2442
Eric Snow6d2cd902018-05-16 15:04:57 -04002443PyDoc_STRVAR(channel_release_doc,
2444"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002445\n\
2446Close the channel for the current interpreter. 'send' and 'recv'\n\
2447(bool) may be used to indicate the ends to close. By default both\n\
2448ends are closed. Closing an already closed end is a noop.");
2449
2450static PyObject *
2451channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2452{
2453 return channelid_new(&ChannelIDtype, args, kwds);
2454}
2455
2456static PyMethodDef module_functions[] = {
2457 {"create", (PyCFunction)interp_create,
2458 METH_VARARGS, create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002459 {"destroy", (PyCFunction)(void(*)(void))interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002460 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302461 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002462 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302463 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002464 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302465 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002466 METH_NOARGS, get_main_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002467 {"is_running", (PyCFunction)(void(*)(void))interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002468 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002469 {"run_string", (PyCFunction)(void(*)(void))interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002470 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002471
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002472 {"is_shareable", (PyCFunction)(void(*)(void))object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002473 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002474
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302475 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002476 METH_NOARGS, channel_create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002477 {"channel_destroy", (PyCFunction)(void(*)(void))channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002478 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302479 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002480 METH_NOARGS, channel_list_all_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002481 {"channel_send", (PyCFunction)(void(*)(void))channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002482 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002483 {"channel_recv", (PyCFunction)(void(*)(void))channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002484 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002485 {"channel_close", (PyCFunction)(void(*)(void))channel_close,
Eric Snow6d2cd902018-05-16 15:04:57 -04002486 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002487 {"channel_release", (PyCFunction)(void(*)(void))channel_release,
Eric Snow6d2cd902018-05-16 15:04:57 -04002488 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002489 {"_channel_id", (PyCFunction)(void(*)(void))channel__channel_id,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002490 METH_VARARGS | METH_KEYWORDS, NULL},
2491
2492 {NULL, NULL} /* sentinel */
2493};
2494
2495
2496/* initialization function */
2497
2498PyDoc_STRVAR(module_doc,
2499"This module provides primitive operations to manage Python interpreters.\n\
2500The 'interpreters' module provides a more convenient interface.");
2501
2502static struct PyModuleDef interpretersmodule = {
2503 PyModuleDef_HEAD_INIT,
2504 "_xxsubinterpreters", /* m_name */
2505 module_doc, /* m_doc */
2506 -1, /* m_size */
2507 module_functions, /* m_methods */
2508 NULL, /* m_slots */
2509 NULL, /* m_traverse */
2510 NULL, /* m_clear */
2511 NULL /* m_free */
2512};
2513
2514
2515PyMODINIT_FUNC
2516PyInit__xxsubinterpreters(void)
2517{
2518 if (_init_globals() != 0) {
2519 return NULL;
2520 }
2521
2522 /* Initialize types */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002523 if (PyType_Ready(&ChannelIDtype) != 0) {
2524 return NULL;
2525 }
2526
2527 /* Create the module */
2528 PyObject *module = PyModule_Create(&interpretersmodule);
2529 if (module == NULL) {
2530 return NULL;
2531 }
2532
2533 /* Add exception types */
2534 PyObject *ns = PyModule_GetDict(module); // borrowed
2535 if (interp_exceptions_init(ns) != 0) {
2536 return NULL;
2537 }
2538 if (channel_exceptions_init(ns) != 0) {
2539 return NULL;
2540 }
2541
2542 /* Add other types */
2543 Py_INCREF(&ChannelIDtype);
2544 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2545 return NULL;
2546 }
Eric Snowc11183c2019-03-15 16:35:46 -06002547 Py_INCREF(&_PyInterpreterID_Type);
2548 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&_PyInterpreterID_Type) != 0) {
Eric Snow4c6955e2018-02-16 18:53:40 -07002549 return NULL;
2550 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002551
Eric Snowc11183c2019-03-15 16:35:46 -06002552 if (_PyCrossInterpreterData_RegisterClass(&ChannelIDtype, _channelid_shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002553 return NULL;
2554 }
2555
2556 return module;
2557}