blob: 4a6ffdd3266783a7359d90eac8d5f81c63f4e7f2 [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";
224 }
225 failure = "unable to encode and copy exception type name";
226 goto finally;
227 }
228
229 if (exc != NULL) {
230 PyObject *msg = PyUnicode_FromFormat("%S", exc);
231 if (msg == NULL) {
232 failure = "unable to format exception message";
233 goto finally;
234 }
235 err->msg = _copy_raw_string(msg);
236 Py_DECREF(msg);
237 if (err->msg == NULL) {
238 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
239 failure = "out of memory copying exception message";
240 }
241 failure = "unable to encode and copy exception message";
242 goto finally;
243 }
244 }
245
246finally:
247 if (failure != NULL) {
248 PyErr_Clear();
249 if (err->name != NULL) {
250 PyMem_Free(err->name);
251 err->name = NULL;
252 }
253 err->msg = failure;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700254 }
255 return err;
256}
257
Eric Snow7f8bfc92018-01-29 18:23:44 -0700258static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700259_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700260{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700261 if (exc->name != NULL) {
262 if (exc->msg != NULL) {
263 PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
264 }
265 else {
266 PyErr_SetString(wrapperclass, exc->name);
267 }
268 }
269 else if (exc->msg != NULL) {
270 PyErr_SetString(wrapperclass, exc->msg);
271 }
272 else {
273 PyErr_SetNone(wrapperclass);
274 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700275}
276
Eric Snow4e9da0d2018-02-02 21:49:49 -0700277
278/* channel-specific code ****************************************************/
Eric Snow7f8bfc92018-01-29 18:23:44 -0700279
Eric Snow3ab01362018-05-17 10:27:09 -0400280#define CHANNEL_SEND 1
281#define CHANNEL_BOTH 0
282#define CHANNEL_RECV -1
283
Eric Snow7f8bfc92018-01-29 18:23:44 -0700284static PyObject *ChannelError;
285static PyObject *ChannelNotFoundError;
286static PyObject *ChannelClosedError;
287static PyObject *ChannelEmptyError;
Eric Snow3ab01362018-05-17 10:27:09 -0400288static PyObject *ChannelNotEmptyError;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700289
290static int
291channel_exceptions_init(PyObject *ns)
292{
293 // XXX Move the exceptions into per-module memory?
294
295 // A channel-related operation failed.
296 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
297 PyExc_RuntimeError, NULL);
298 if (ChannelError == NULL) {
299 return -1;
300 }
301 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
302 return -1;
303 }
304
305 // An operation tried to use a channel that doesn't exist.
306 ChannelNotFoundError = PyErr_NewException(
307 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
308 if (ChannelNotFoundError == NULL) {
309 return -1;
310 }
311 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
312 return -1;
313 }
314
315 // An operation tried to use a closed channel.
316 ChannelClosedError = PyErr_NewException(
317 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
318 if (ChannelClosedError == NULL) {
319 return -1;
320 }
321 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
322 return -1;
323 }
324
325 // An operation tried to pop from an empty channel.
326 ChannelEmptyError = PyErr_NewException(
327 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
328 if (ChannelEmptyError == NULL) {
329 return -1;
330 }
331 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
332 return -1;
333 }
334
Eric Snow3ab01362018-05-17 10:27:09 -0400335 // An operation tried to close a non-empty channel.
336 ChannelNotEmptyError = PyErr_NewException(
337 "_xxsubinterpreters.ChannelNotEmptyError", ChannelError, NULL);
338 if (ChannelNotEmptyError == NULL) {
339 return -1;
340 }
341 if (PyDict_SetItemString(ns, "ChannelNotEmptyError", ChannelNotEmptyError) != 0) {
342 return -1;
343 }
344
Eric Snow7f8bfc92018-01-29 18:23:44 -0700345 return 0;
346}
347
Eric Snow4e9da0d2018-02-02 21:49:49 -0700348/* the channel queue */
349
350struct _channelitem;
351
352typedef struct _channelitem {
353 _PyCrossInterpreterData *data;
354 struct _channelitem *next;
355} _channelitem;
356
357static _channelitem *
358_channelitem_new(void)
359{
360 _channelitem *item = PyMem_NEW(_channelitem, 1);
361 if (item == NULL) {
362 PyErr_NoMemory();
363 return NULL;
364 }
365 item->data = NULL;
366 item->next = NULL;
367 return item;
368}
369
370static void
371_channelitem_clear(_channelitem *item)
372{
373 if (item->data != NULL) {
374 _PyCrossInterpreterData_Release(item->data);
375 PyMem_Free(item->data);
376 item->data = NULL;
377 }
378 item->next = NULL;
379}
380
381static void
382_channelitem_free(_channelitem *item)
383{
384 _channelitem_clear(item);
385 PyMem_Free(item);
386}
387
388static void
389_channelitem_free_all(_channelitem *item)
390{
391 while (item != NULL) {
392 _channelitem *last = item;
393 item = item->next;
394 _channelitem_free(last);
395 }
396}
397
398static _PyCrossInterpreterData *
399_channelitem_popped(_channelitem *item)
400{
401 _PyCrossInterpreterData *data = item->data;
402 item->data = NULL;
403 _channelitem_free(item);
404 return data;
405}
406
407typedef struct _channelqueue {
408 int64_t count;
409 _channelitem *first;
410 _channelitem *last;
411} _channelqueue;
412
413static _channelqueue *
414_channelqueue_new(void)
415{
416 _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
417 if (queue == NULL) {
418 PyErr_NoMemory();
419 return NULL;
420 }
421 queue->count = 0;
422 queue->first = NULL;
423 queue->last = NULL;
424 return queue;
425}
426
427static void
428_channelqueue_clear(_channelqueue *queue)
429{
430 _channelitem_free_all(queue->first);
431 queue->count = 0;
432 queue->first = NULL;
433 queue->last = NULL;
434}
435
436static void
437_channelqueue_free(_channelqueue *queue)
438{
439 _channelqueue_clear(queue);
440 PyMem_Free(queue);
441}
442
443static int
444_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
445{
446 _channelitem *item = _channelitem_new();
447 if (item == NULL) {
448 return -1;
449 }
450 item->data = data;
451
452 queue->count += 1;
453 if (queue->first == NULL) {
454 queue->first = item;
455 }
456 else {
457 queue->last->next = item;
458 }
459 queue->last = item;
460 return 0;
461}
462
463static _PyCrossInterpreterData *
464_channelqueue_get(_channelqueue *queue)
465{
466 _channelitem *item = queue->first;
467 if (item == NULL) {
468 return NULL;
469 }
470 queue->first = item->next;
471 if (queue->last == item) {
472 queue->last = NULL;
473 }
474 queue->count -= 1;
475
476 return _channelitem_popped(item);
477}
478
479/* channel-interpreter associations */
480
Eric Snow7f8bfc92018-01-29 18:23:44 -0700481struct _channelend;
482
483typedef struct _channelend {
484 struct _channelend *next;
485 int64_t interp;
486 int open;
487} _channelend;
488
489static _channelend *
490_channelend_new(int64_t interp)
491{
492 _channelend *end = PyMem_NEW(_channelend, 1);
493 if (end == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700494 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700495 return NULL;
496 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700497 end->next = NULL;
498 end->interp = interp;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700499 end->open = 1;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700500 return end;
501}
502
503static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700504_channelend_free(_channelend *end)
505{
506 PyMem_Free(end);
507}
508
509static void
510_channelend_free_all(_channelend *end)
511{
Eric Snow7f8bfc92018-01-29 18:23:44 -0700512 while (end != NULL) {
513 _channelend *last = end;
514 end = end->next;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700515 _channelend_free(last);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700516 }
517}
518
519static _channelend *
520_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
521{
522 _channelend *prev = NULL;
523 _channelend *end = first;
524 while (end != NULL) {
525 if (end->interp == interp) {
526 break;
527 }
528 prev = end;
529 end = end->next;
530 }
531 if (pprev != NULL) {
532 *pprev = prev;
533 }
534 return end;
535}
536
Eric Snow4e9da0d2018-02-02 21:49:49 -0700537typedef struct _channelassociations {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700538 // Note that the list entries are never removed for interpreter
539 // for which the channel is closed. This should be a problem in
540 // practice. Also, a channel isn't automatically closed when an
541 // interpreter is destroyed.
542 int64_t numsendopen;
543 int64_t numrecvopen;
544 _channelend *send;
545 _channelend *recv;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700546} _channelends;
547
548static _channelends *
549_channelends_new(void)
550{
551 _channelends *ends = PyMem_NEW(_channelends, 1);
552 if (ends== NULL) {
553 return NULL;
554 }
555 ends->numsendopen = 0;
556 ends->numrecvopen = 0;
557 ends->send = NULL;
558 ends->recv = NULL;
559 return ends;
560}
561
562static void
563_channelends_clear(_channelends *ends)
564{
565 _channelend_free_all(ends->send);
566 ends->send = NULL;
567 ends->numsendopen = 0;
568
569 _channelend_free_all(ends->recv);
570 ends->recv = NULL;
571 ends->numrecvopen = 0;
572}
573
574static void
575_channelends_free(_channelends *ends)
576{
577 _channelends_clear(ends);
578 PyMem_Free(ends);
579}
580
581static _channelend *
582_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
583 int send)
584{
585 _channelend *end = _channelend_new(interp);
586 if (end == NULL) {
587 return NULL;
588 }
589
590 if (prev == NULL) {
591 if (send) {
592 ends->send = end;
593 }
594 else {
595 ends->recv = end;
596 }
597 }
598 else {
599 prev->next = end;
600 }
601 if (send) {
602 ends->numsendopen += 1;
603 }
604 else {
605 ends->numrecvopen += 1;
606 }
607 return end;
608}
609
610static int
611_channelends_associate(_channelends *ends, int64_t interp, int send)
612{
613 _channelend *prev;
614 _channelend *end = _channelend_find(send ? ends->send : ends->recv,
615 interp, &prev);
616 if (end != NULL) {
617 if (!end->open) {
618 PyErr_SetString(ChannelClosedError, "channel already closed");
619 return -1;
620 }
621 // already associated
622 return 0;
623 }
624 if (_channelends_add(ends, prev, interp, send) == NULL) {
625 return -1;
626 }
627 return 0;
628}
629
630static int
631_channelends_is_open(_channelends *ends)
632{
633 if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
634 return 1;
635 }
636 if (ends->send == NULL && ends->recv == NULL) {
637 return 1;
638 }
639 return 0;
640}
641
642static void
643_channelends_close_end(_channelends *ends, _channelend *end, int send)
644{
645 end->open = 0;
646 if (send) {
647 ends->numsendopen -= 1;
648 }
649 else {
650 ends->numrecvopen -= 1;
651 }
652}
653
654static int
655_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
656{
657 _channelend *prev;
658 _channelend *end;
659 if (which >= 0) { // send/both
660 end = _channelend_find(ends->send, interp, &prev);
661 if (end == NULL) {
662 // never associated so add it
663 end = _channelends_add(ends, prev, interp, 1);
664 if (end == NULL) {
665 return -1;
666 }
667 }
668 _channelends_close_end(ends, end, 1);
669 }
670 if (which <= 0) { // recv/both
671 end = _channelend_find(ends->recv, interp, &prev);
672 if (end == NULL) {
673 // never associated so add it
674 end = _channelends_add(ends, prev, interp, 0);
675 if (end == NULL) {
676 return -1;
677 }
678 }
679 _channelends_close_end(ends, end, 0);
680 }
681 return 0;
682}
683
684static void
Eric Snow3ab01362018-05-17 10:27:09 -0400685_channelends_close_all(_channelends *ends, int which, int force)
Eric Snow4e9da0d2018-02-02 21:49:49 -0700686{
Eric Snow3ab01362018-05-17 10:27:09 -0400687 // XXX Handle the ends.
688 // XXX Handle force is True.
689
Eric Snow4e9da0d2018-02-02 21:49:49 -0700690 // Ensure all the "send"-associated interpreters are closed.
691 _channelend *end;
692 for (end = ends->send; end != NULL; end = end->next) {
693 _channelends_close_end(ends, end, 1);
694 }
695
696 // Ensure all the "recv"-associated interpreters are closed.
697 for (end = ends->recv; end != NULL; end = end->next) {
698 _channelends_close_end(ends, end, 0);
699 }
700}
701
702/* channels */
703
704struct _channel;
Eric Snow3ab01362018-05-17 10:27:09 -0400705struct _channel_closing;
706static void _channel_clear_closing(struct _channel *);
707static void _channel_finish_closing(struct _channel *);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700708
709typedef struct _channel {
710 PyThread_type_lock mutex;
711 _channelqueue *queue;
712 _channelends *ends;
713 int open;
Eric Snow3ab01362018-05-17 10:27:09 -0400714 struct _channel_closing *closing;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700715} _PyChannelState;
716
717static _PyChannelState *
718_channel_new(void)
719{
720 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
721 if (chan == NULL) {
722 return NULL;
723 }
724 chan->mutex = PyThread_allocate_lock();
725 if (chan->mutex == NULL) {
726 PyMem_Free(chan);
727 PyErr_SetString(ChannelError,
728 "can't initialize mutex for new channel");
729 return NULL;
730 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700731 chan->queue = _channelqueue_new();
732 if (chan->queue == NULL) {
733 PyMem_Free(chan);
734 return NULL;
735 }
736 chan->ends = _channelends_new();
737 if (chan->ends == NULL) {
738 _channelqueue_free(chan->queue);
739 PyMem_Free(chan);
740 return NULL;
741 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700742 chan->open = 1;
Eric Snow3ab01362018-05-17 10:27:09 -0400743 chan->closing = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700744 return chan;
745}
746
Eric Snow4e9da0d2018-02-02 21:49:49 -0700747static void
748_channel_free(_PyChannelState *chan)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700749{
Eric Snow3ab01362018-05-17 10:27:09 -0400750 _channel_clear_closing(chan);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700751 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
752 _channelqueue_free(chan->queue);
753 _channelends_free(chan->ends);
754 PyThread_release_lock(chan->mutex);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700755
Eric Snow4e9da0d2018-02-02 21:49:49 -0700756 PyThread_free_lock(chan->mutex);
757 PyMem_Free(chan);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700758}
759
Eric Snow4e9da0d2018-02-02 21:49:49 -0700760static int
761_channel_add(_PyChannelState *chan, int64_t interp,
762 _PyCrossInterpreterData *data)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700763{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700764 int res = -1;
765 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
766
Eric Snow7f8bfc92018-01-29 18:23:44 -0700767 if (!chan->open) {
768 PyErr_SetString(ChannelClosedError, "channel closed");
Eric Snow4e9da0d2018-02-02 21:49:49 -0700769 goto done;
770 }
771 if (_channelends_associate(chan->ends, interp, 1) != 0) {
772 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700773 }
774
Eric Snow4e9da0d2018-02-02 21:49:49 -0700775 if (_channelqueue_put(chan->queue, data) != 0) {
776 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700777 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700778
779 res = 0;
780done:
781 PyThread_release_lock(chan->mutex);
782 return res;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700783}
784
Eric Snow4e9da0d2018-02-02 21:49:49 -0700785static _PyCrossInterpreterData *
786_channel_next(_PyChannelState *chan, int64_t interp)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700787{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700788 _PyCrossInterpreterData *data = NULL;
789 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
790
791 if (!chan->open) {
792 PyErr_SetString(ChannelClosedError, "channel closed");
793 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700794 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700795 if (_channelends_associate(chan->ends, interp, 0) != 0) {
796 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700797 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700798
799 data = _channelqueue_get(chan->queue);
Eric Snow3ab01362018-05-17 10:27:09 -0400800 if (data == NULL && !PyErr_Occurred() && chan->closing != NULL) {
801 chan->open = 0;
802 }
803
Eric Snow4e9da0d2018-02-02 21:49:49 -0700804done:
805 PyThread_release_lock(chan->mutex);
Eric Snow3ab01362018-05-17 10:27:09 -0400806 if (chan->queue->count == 0) {
807 _channel_finish_closing(chan);
808 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700809 return data;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700810}
811
812static int
Eric Snow3ab01362018-05-17 10:27:09 -0400813_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700814{
815 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
816
817 int res = -1;
818 if (!chan->open) {
819 PyErr_SetString(ChannelClosedError, "channel already closed");
820 goto done;
821 }
822
Eric Snow3ab01362018-05-17 10:27:09 -0400823 if (_channelends_close_interpreter(chan->ends, interp, end) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700824 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700825 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700826 chan->open = _channelends_is_open(chan->ends);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700827
828 res = 0;
829done:
830 PyThread_release_lock(chan->mutex);
831 return res;
832}
833
834static int
Eric Snow3ab01362018-05-17 10:27:09 -0400835_channel_close_all(_PyChannelState *chan, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700836{
837 int res = -1;
838 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
839
840 if (!chan->open) {
841 PyErr_SetString(ChannelClosedError, "channel already closed");
842 goto done;
843 }
844
Eric Snow3ab01362018-05-17 10:27:09 -0400845 if (!force && chan->queue->count > 0) {
846 PyErr_SetString(ChannelNotEmptyError,
847 "may not be closed if not empty (try force=True)");
848 goto done;
849 }
850
Eric Snow7f8bfc92018-01-29 18:23:44 -0700851 chan->open = 0;
852
853 // We *could* also just leave these in place, since we've marked
854 // the channel as closed already.
Eric Snow3ab01362018-05-17 10:27:09 -0400855 _channelends_close_all(chan->ends, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700856
857 res = 0;
858done:
859 PyThread_release_lock(chan->mutex);
860 return res;
861}
862
Eric Snow4e9da0d2018-02-02 21:49:49 -0700863/* the set of channels */
Eric Snow7f8bfc92018-01-29 18:23:44 -0700864
865struct _channelref;
866
867typedef struct _channelref {
868 int64_t id;
869 _PyChannelState *chan;
870 struct _channelref *next;
871 Py_ssize_t objcount;
872} _channelref;
873
874static _channelref *
875_channelref_new(int64_t id, _PyChannelState *chan)
876{
877 _channelref *ref = PyMem_NEW(_channelref, 1);
878 if (ref == NULL) {
879 return NULL;
880 }
881 ref->id = id;
882 ref->chan = chan;
883 ref->next = NULL;
884 ref->objcount = 0;
885 return ref;
886}
887
Eric Snow4e9da0d2018-02-02 21:49:49 -0700888//static void
889//_channelref_clear(_channelref *ref)
890//{
891// ref->id = -1;
892// ref->chan = NULL;
893// ref->next = NULL;
894// ref->objcount = 0;
895//}
896
897static void
898_channelref_free(_channelref *ref)
899{
Eric Snow3ab01362018-05-17 10:27:09 -0400900 if (ref->chan != NULL) {
901 _channel_clear_closing(ref->chan);
902 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700903 //_channelref_clear(ref);
904 PyMem_Free(ref);
905}
906
Eric Snow7f8bfc92018-01-29 18:23:44 -0700907static _channelref *
908_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
909{
910 _channelref *prev = NULL;
911 _channelref *ref = first;
912 while (ref != NULL) {
913 if (ref->id == id) {
914 break;
915 }
916 prev = ref;
917 ref = ref->next;
918 }
919 if (pprev != NULL) {
920 *pprev = prev;
921 }
922 return ref;
923}
924
925typedef struct _channels {
926 PyThread_type_lock mutex;
927 _channelref *head;
928 int64_t numopen;
929 int64_t next_id;
930} _channels;
931
932static int
933_channels_init(_channels *channels)
934{
935 if (channels->mutex == NULL) {
936 channels->mutex = PyThread_allocate_lock();
937 if (channels->mutex == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700938 PyErr_SetString(ChannelError,
939 "can't initialize mutex for channel management");
940 return -1;
941 }
942 }
943 channels->head = NULL;
944 channels->numopen = 0;
945 channels->next_id = 0;
946 return 0;
947}
948
949static int64_t
950_channels_next_id(_channels *channels) // needs lock
951{
952 int64_t id = channels->next_id;
953 if (id < 0) {
954 /* overflow */
955 PyErr_SetString(ChannelError,
956 "failed to get a channel ID");
957 return -1;
958 }
959 channels->next_id += 1;
960 return id;
961}
962
963static _PyChannelState *
964_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
965{
966 _PyChannelState *chan = NULL;
967 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
968 if (pmutex != NULL) {
969 *pmutex = NULL;
970 }
971
972 _channelref *ref = _channelref_find(channels->head, id, NULL);
973 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -0600974 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700975 goto done;
976 }
977 if (ref->chan == NULL || !ref->chan->open) {
Eric Snowab4a1982018-06-13 08:02:39 -0600978 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700979 goto done;
980 }
981
982 if (pmutex != NULL) {
983 // The mutex will be closed by the caller.
984 *pmutex = channels->mutex;
985 }
986
987 chan = ref->chan;
988done:
989 if (pmutex == NULL || *pmutex == NULL) {
990 PyThread_release_lock(channels->mutex);
991 }
992 return chan;
993}
994
995static int64_t
996_channels_add(_channels *channels, _PyChannelState *chan)
997{
998 int64_t cid = -1;
999 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1000
1001 // Create a new ref.
1002 int64_t id = _channels_next_id(channels);
1003 if (id < 0) {
1004 goto done;
1005 }
1006 _channelref *ref = _channelref_new(id, chan);
1007 if (ref == NULL) {
1008 goto done;
1009 }
1010
1011 // Add it to the list.
1012 // We assume that the channel is a new one (not already in the list).
1013 ref->next = channels->head;
1014 channels->head = ref;
1015 channels->numopen += 1;
1016
1017 cid = id;
1018done:
1019 PyThread_release_lock(channels->mutex);
1020 return cid;
1021}
1022
Eric Snow3ab01362018-05-17 10:27:09 -04001023/* forward */
1024static int _channel_set_closing(struct _channelref *, PyThread_type_lock);
1025
Eric Snow7f8bfc92018-01-29 18:23:44 -07001026static int
Eric Snow3ab01362018-05-17 10:27:09 -04001027_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan,
1028 int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001029{
1030 int res = -1;
1031 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1032 if (pchan != NULL) {
1033 *pchan = NULL;
1034 }
1035
1036 _channelref *ref = _channelref_find(channels->head, cid, NULL);
1037 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001038 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001039 goto done;
1040 }
1041
1042 if (ref->chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001043 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001044 goto done;
1045 }
Eric Snow3ab01362018-05-17 10:27:09 -04001046 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001047 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001048 goto done;
1049 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001050 else {
Eric Snow3ab01362018-05-17 10:27:09 -04001051 if (_channel_close_all(ref->chan, end, force) != 0) {
1052 if (end == CHANNEL_SEND &&
1053 PyErr_ExceptionMatches(ChannelNotEmptyError)) {
1054 if (ref->chan->closing != NULL) {
Eric Snow6854e802018-06-01 16:26:01 -06001055 PyErr_Format(ChannelClosedError,
Eric Snowab4a1982018-06-13 08:02:39 -06001056 "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001057 goto done;
1058 }
1059 // Mark the channel as closing and return. The channel
1060 // will be cleaned up in _channel_next().
1061 PyErr_Clear();
1062 if (_channel_set_closing(ref, channels->mutex) != 0) {
1063 goto done;
1064 }
1065 if (pchan != NULL) {
1066 *pchan = ref->chan;
1067 }
1068 res = 0;
1069 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001070 goto done;
1071 }
1072 if (pchan != NULL) {
1073 *pchan = ref->chan;
1074 }
Eric Snow3ab01362018-05-17 10:27:09 -04001075 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001076 _channel_free(ref->chan);
1077 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001078 ref->chan = NULL;
1079 }
1080
1081 res = 0;
1082done:
1083 PyThread_release_lock(channels->mutex);
1084 return res;
1085}
1086
1087static void
1088_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1089 _PyChannelState **pchan)
1090{
1091 if (ref == channels->head) {
1092 channels->head = ref->next;
1093 }
1094 else {
1095 prev->next = ref->next;
1096 }
1097 channels->numopen -= 1;
1098
1099 if (pchan != NULL) {
1100 *pchan = ref->chan;
1101 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001102 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001103}
1104
1105static int
1106_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1107{
1108 int res = -1;
1109 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1110
1111 if (pchan != NULL) {
1112 *pchan = NULL;
1113 }
1114
1115 _channelref *prev = NULL;
1116 _channelref *ref = _channelref_find(channels->head, id, &prev);
1117 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001118 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001119 goto done;
1120 }
1121
1122 _channels_remove_ref(channels, ref, prev, pchan);
1123
1124 res = 0;
1125done:
1126 PyThread_release_lock(channels->mutex);
1127 return res;
1128}
1129
1130static int
1131_channels_add_id_object(_channels *channels, int64_t id)
1132{
1133 int res = -1;
1134 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1135
1136 _channelref *ref = _channelref_find(channels->head, id, NULL);
1137 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001138 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001139 goto done;
1140 }
1141 ref->objcount += 1;
1142
1143 res = 0;
1144done:
1145 PyThread_release_lock(channels->mutex);
1146 return res;
1147}
1148
1149static void
1150_channels_drop_id_object(_channels *channels, int64_t id)
1151{
1152 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1153
1154 _channelref *prev = NULL;
1155 _channelref *ref = _channelref_find(channels->head, id, &prev);
1156 if (ref == NULL) {
1157 // Already destroyed.
1158 goto done;
1159 }
1160 ref->objcount -= 1;
1161
1162 // Destroy if no longer used.
1163 if (ref->objcount == 0) {
1164 _PyChannelState *chan = NULL;
1165 _channels_remove_ref(channels, ref, prev, &chan);
1166 if (chan != NULL) {
1167 _channel_free(chan);
1168 }
1169 }
1170
1171done:
1172 PyThread_release_lock(channels->mutex);
1173}
1174
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001175static int64_t *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001176_channels_list_all(_channels *channels, int64_t *count)
1177{
1178 int64_t *cids = NULL;
1179 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1180 int64_t numopen = channels->numopen;
1181 if (numopen >= PY_SSIZE_T_MAX) {
1182 PyErr_SetString(PyExc_RuntimeError, "too many channels open");
1183 goto done;
1184 }
1185 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
1186 if (ids == NULL) {
1187 goto done;
1188 }
1189 _channelref *ref = channels->head;
1190 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
1191 ids[i] = ref->id;
1192 }
1193 *count = channels->numopen;
1194
1195 cids = ids;
1196done:
1197 PyThread_release_lock(channels->mutex);
1198 return cids;
1199}
1200
Eric Snow3ab01362018-05-17 10:27:09 -04001201/* support for closing non-empty channels */
1202
1203struct _channel_closing {
1204 struct _channelref *ref;
1205};
1206
1207static int
1208_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
1209 struct _channel *chan = ref->chan;
1210 if (chan == NULL) {
1211 // already closed
1212 return 0;
1213 }
1214 int res = -1;
1215 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1216 if (chan->closing != NULL) {
1217 PyErr_SetString(ChannelClosedError, "channel closed");
1218 goto done;
1219 }
1220 chan->closing = PyMem_NEW(struct _channel_closing, 1);
1221 if (chan->closing == NULL) {
1222 goto done;
1223 }
1224 chan->closing->ref = ref;
1225
1226 res = 0;
1227done:
1228 PyThread_release_lock(chan->mutex);
1229 return res;
1230}
1231
1232static void
1233_channel_clear_closing(struct _channel *chan) {
1234 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1235 if (chan->closing != NULL) {
1236 PyMem_Free(chan->closing);
1237 chan->closing = NULL;
1238 }
1239 PyThread_release_lock(chan->mutex);
1240}
1241
1242static void
1243_channel_finish_closing(struct _channel *chan) {
1244 struct _channel_closing *closing = chan->closing;
1245 if (closing == NULL) {
1246 return;
1247 }
1248 _channelref *ref = closing->ref;
1249 _channel_clear_closing(chan);
1250 // Do the things that would have been done in _channels_close().
1251 ref->chan = NULL;
1252 _channel_free(chan);
Zackery Spytz1a2252e2019-05-06 10:56:51 -06001253}
Eric Snow3ab01362018-05-17 10:27:09 -04001254
Eric Snow7f8bfc92018-01-29 18:23:44 -07001255/* "high"-level channel-related functions */
1256
1257static int64_t
1258_channel_create(_channels *channels)
1259{
1260 _PyChannelState *chan = _channel_new();
1261 if (chan == NULL) {
1262 return -1;
1263 }
1264 int64_t id = _channels_add(channels, chan);
1265 if (id < 0) {
1266 _channel_free(chan);
1267 return -1;
1268 }
1269 return id;
1270}
1271
1272static int
1273_channel_destroy(_channels *channels, int64_t id)
1274{
1275 _PyChannelState *chan = NULL;
1276 if (_channels_remove(channels, id, &chan) != 0) {
1277 return -1;
1278 }
1279 if (chan != NULL) {
1280 _channel_free(chan);
1281 }
1282 return 0;
1283}
1284
1285static int
1286_channel_send(_channels *channels, int64_t id, PyObject *obj)
1287{
1288 PyInterpreterState *interp = _get_current();
1289 if (interp == NULL) {
1290 return -1;
1291 }
1292
1293 // Look up the channel.
1294 PyThread_type_lock mutex = NULL;
1295 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1296 if (chan == NULL) {
1297 return -1;
1298 }
1299 // Past this point we are responsible for releasing the mutex.
1300
Eric Snow3ab01362018-05-17 10:27:09 -04001301 if (chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001302 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow3ab01362018-05-17 10:27:09 -04001303 PyThread_release_lock(mutex);
1304 return -1;
1305 }
1306
Eric Snow7f8bfc92018-01-29 18:23:44 -07001307 // Convert the object to cross-interpreter data.
1308 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
1309 if (data == NULL) {
1310 PyThread_release_lock(mutex);
1311 return -1;
1312 }
1313 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
Victor Stinner4d61e6e2019-03-04 14:21:28 +01001314 PyThread_release_lock(mutex);
Eric Snowc11183c2019-03-15 16:35:46 -06001315 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001316 return -1;
1317 }
1318
1319 // Add the data to the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06001320 int res = _channel_add(chan, PyInterpreterState_GetID(interp), data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001321 PyThread_release_lock(mutex);
1322 if (res != 0) {
1323 _PyCrossInterpreterData_Release(data);
1324 PyMem_Free(data);
1325 return -1;
1326 }
1327
1328 return 0;
1329}
1330
1331static PyObject *
1332_channel_recv(_channels *channels, int64_t id)
1333{
1334 PyInterpreterState *interp = _get_current();
1335 if (interp == NULL) {
1336 return NULL;
1337 }
1338
1339 // Look up the channel.
1340 PyThread_type_lock mutex = NULL;
1341 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1342 if (chan == NULL) {
1343 return NULL;
1344 }
1345 // Past this point we are responsible for releasing the mutex.
1346
1347 // Pop off the next item from the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06001348 _PyCrossInterpreterData *data = _channel_next(chan, PyInterpreterState_GetID(interp));
Eric Snow7f8bfc92018-01-29 18:23:44 -07001349 PyThread_release_lock(mutex);
1350 if (data == NULL) {
Eric Snow6d2cd902018-05-16 15:04:57 -04001351 if (!PyErr_Occurred()) {
Eric Snowab4a1982018-06-13 08:02:39 -06001352 PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001353 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001354 return NULL;
1355 }
1356
1357 // Convert the data back to an object.
1358 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
1359 if (obj == NULL) {
1360 return NULL;
1361 }
1362 _PyCrossInterpreterData_Release(data);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001363 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001364
1365 return obj;
1366}
1367
1368static int
1369_channel_drop(_channels *channels, int64_t id, int send, int recv)
1370{
1371 PyInterpreterState *interp = _get_current();
1372 if (interp == NULL) {
1373 return -1;
1374 }
1375
1376 // Look up the channel.
1377 PyThread_type_lock mutex = NULL;
1378 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1379 if (chan == NULL) {
1380 return -1;
1381 }
1382 // Past this point we are responsible for releasing the mutex.
1383
1384 // Close one or both of the two ends.
Eric Snowc11183c2019-03-15 16:35:46 -06001385 int res = _channel_close_interpreter(chan, PyInterpreterState_GetID(interp), send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001386 PyThread_release_lock(mutex);
1387 return res;
1388}
1389
1390static int
Eric Snow3ab01362018-05-17 10:27:09 -04001391_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001392{
Eric Snow3ab01362018-05-17 10:27:09 -04001393 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001394}
1395
1396/* ChannelID class */
1397
Eric Snow7f8bfc92018-01-29 18:23:44 -07001398static PyTypeObject ChannelIDtype;
1399
1400typedef struct channelid {
1401 PyObject_HEAD
1402 int64_t id;
1403 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001404 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001405 _channels *channels;
1406} channelid;
1407
Serhiy Storchakabf169912019-09-13 22:50:27 +03001408static int
1409channel_id_converter(PyObject *arg, void *ptr)
1410{
1411 int64_t cid;
1412 if (PyObject_TypeCheck(arg, &ChannelIDtype)) {
1413 cid = ((channelid *)arg)->id;
1414 }
1415 else if (PyIndex_Check(arg)) {
1416 cid = PyLong_AsLongLong(arg);
1417 if (cid == -1 && PyErr_Occurred()) {
1418 return 0;
1419 }
1420 if (cid < 0) {
1421 PyErr_Format(PyExc_ValueError,
1422 "channel ID must be a non-negative int, got %R", arg);
1423 return 0;
1424 }
1425 }
1426 else {
1427 PyErr_Format(PyExc_TypeError,
1428 "channel ID must be an int, got %.100s",
1429 arg->ob_type->tp_name);
1430 return 0;
1431 }
1432 *(int64_t *)ptr = cid;
1433 return 1;
1434}
1435
Eric Snow7f8bfc92018-01-29 18:23:44 -07001436static channelid *
1437newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001438 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001439{
1440 channelid *self = PyObject_New(channelid, cls);
1441 if (self == NULL) {
1442 return NULL;
1443 }
1444 self->id = cid;
1445 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001446 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001447 self->channels = channels;
1448
1449 if (_channels_add_id_object(channels, cid) != 0) {
1450 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1451 PyErr_Clear();
1452 }
1453 else {
1454 Py_DECREF((PyObject *)self);
1455 return NULL;
1456 }
1457 }
1458
1459 return self;
1460}
1461
1462static _channels * _global_channels(void);
1463
1464static PyObject *
1465channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1466{
Eric Snow6d2cd902018-05-16 15:04:57 -04001467 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03001468 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001469 int send = -1;
1470 int recv = -1;
1471 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001472 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001473 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03001474 "O&|$pppp:ChannelID.__new__", kwlist,
1475 channel_id_converter, &cid, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001476 return NULL;
1477
Eric Snow7f8bfc92018-01-29 18:23:44 -07001478 // Handle "send" and "recv".
1479 if (send == 0 && recv == 0) {
1480 PyErr_SetString(PyExc_ValueError,
1481 "'send' and 'recv' cannot both be False");
1482 return NULL;
1483 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001484
Eric Snow7f8bfc92018-01-29 18:23:44 -07001485 int end = 0;
1486 if (send == 1) {
1487 if (recv == 0 || recv == -1) {
1488 end = CHANNEL_SEND;
1489 }
1490 }
1491 else if (recv == 1) {
1492 end = CHANNEL_RECV;
1493 }
1494
Eric Snow6d2cd902018-05-16 15:04:57 -04001495 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
1496 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001497}
1498
1499static void
1500channelid_dealloc(PyObject *v)
1501{
1502 int64_t cid = ((channelid *)v)->id;
1503 _channels *channels = ((channelid *)v)->channels;
1504 Py_TYPE(v)->tp_free(v);
1505
1506 _channels_drop_id_object(channels, cid);
1507}
1508
1509static PyObject *
1510channelid_repr(PyObject *self)
1511{
1512 PyTypeObject *type = Py_TYPE(self);
1513 const char *name = _PyType_Name(type);
1514
1515 channelid *cid = (channelid *)self;
1516 const char *fmt;
1517 if (cid->end == CHANNEL_SEND) {
Eric Snowab4a1982018-06-13 08:02:39 -06001518 fmt = "%s(%" PRId64 ", send=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001519 }
1520 else if (cid->end == CHANNEL_RECV) {
Eric Snowab4a1982018-06-13 08:02:39 -06001521 fmt = "%s(%" PRId64 ", recv=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001522 }
1523 else {
Eric Snowab4a1982018-06-13 08:02:39 -06001524 fmt = "%s(%" PRId64 ")";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001525 }
1526 return PyUnicode_FromFormat(fmt, name, cid->id);
1527}
1528
Eric Snow6d2cd902018-05-16 15:04:57 -04001529static PyObject *
1530channelid_str(PyObject *self)
1531{
1532 channelid *cid = (channelid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06001533 return PyUnicode_FromFormat("%" PRId64 "", cid->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001534}
1535
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001536static PyObject *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001537channelid_int(PyObject *self)
1538{
1539 channelid *cid = (channelid *)self;
1540 return PyLong_FromLongLong(cid->id);
1541}
1542
1543static PyNumberMethods channelid_as_number = {
1544 0, /* nb_add */
1545 0, /* nb_subtract */
1546 0, /* nb_multiply */
1547 0, /* nb_remainder */
1548 0, /* nb_divmod */
1549 0, /* nb_power */
1550 0, /* nb_negative */
1551 0, /* nb_positive */
1552 0, /* nb_absolute */
1553 0, /* nb_bool */
1554 0, /* nb_invert */
1555 0, /* nb_lshift */
1556 0, /* nb_rshift */
1557 0, /* nb_and */
1558 0, /* nb_xor */
1559 0, /* nb_or */
1560 (unaryfunc)channelid_int, /* nb_int */
1561 0, /* nb_reserved */
1562 0, /* nb_float */
1563
1564 0, /* nb_inplace_add */
1565 0, /* nb_inplace_subtract */
1566 0, /* nb_inplace_multiply */
1567 0, /* nb_inplace_remainder */
1568 0, /* nb_inplace_power */
1569 0, /* nb_inplace_lshift */
1570 0, /* nb_inplace_rshift */
1571 0, /* nb_inplace_and */
1572 0, /* nb_inplace_xor */
1573 0, /* nb_inplace_or */
1574
1575 0, /* nb_floor_divide */
1576 0, /* nb_true_divide */
1577 0, /* nb_inplace_floor_divide */
1578 0, /* nb_inplace_true_divide */
1579
1580 (unaryfunc)channelid_int, /* nb_index */
1581};
1582
1583static Py_hash_t
1584channelid_hash(PyObject *self)
1585{
1586 channelid *cid = (channelid *)self;
1587 PyObject *id = PyLong_FromLongLong(cid->id);
1588 if (id == NULL) {
1589 return -1;
1590 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001591 Py_hash_t hash = PyObject_Hash(id);
1592 Py_DECREF(id);
1593 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001594}
1595
1596static PyObject *
1597channelid_richcompare(PyObject *self, PyObject *other, int op)
1598{
1599 if (op != Py_EQ && op != Py_NE) {
1600 Py_RETURN_NOTIMPLEMENTED;
1601 }
1602
1603 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1604 Py_RETURN_NOTIMPLEMENTED;
1605 }
1606
1607 channelid *cid = (channelid *)self;
1608 int equal;
1609 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1610 channelid *othercid = (channelid *)other;
Serhiy Storchakabf169912019-09-13 22:50:27 +03001611 equal = (cid->end == othercid->end) && (cid->id == othercid->id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001612 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001613 else if (PyLong_Check(other)) {
1614 /* Fast path */
1615 int overflow;
1616 long long othercid = PyLong_AsLongLongAndOverflow(other, &overflow);
1617 if (othercid == -1 && PyErr_Occurred()) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001618 return NULL;
1619 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001620 equal = !overflow && (othercid >= 0) && (cid->id == othercid);
1621 }
1622 else if (PyNumber_Check(other)) {
1623 PyObject *pyid = PyLong_FromLongLong(cid->id);
1624 if (pyid == NULL) {
1625 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001626 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001627 PyObject *res = PyObject_RichCompare(pyid, other, op);
1628 Py_DECREF(pyid);
1629 return res;
1630 }
1631 else {
1632 Py_RETURN_NOTIMPLEMENTED;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001633 }
1634
1635 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1636 Py_RETURN_TRUE;
1637 }
1638 Py_RETURN_FALSE;
1639}
1640
Eric Snowab4a1982018-06-13 08:02:39 -06001641static PyObject *
1642_channel_from_cid(PyObject *cid, int end)
1643{
1644 PyObject *highlevel = PyImport_ImportModule("interpreters");
1645 if (highlevel == NULL) {
1646 PyErr_Clear();
1647 highlevel = PyImport_ImportModule("test.support.interpreters");
1648 if (highlevel == NULL) {
1649 return NULL;
1650 }
1651 }
1652 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
1653 "SendChannel";
1654 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1655 Py_DECREF(highlevel);
1656 if (cls == NULL) {
1657 return NULL;
1658 }
1659 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1660 Py_DECREF(cls);
1661 if (chan == NULL) {
1662 return NULL;
1663 }
1664 return chan;
1665}
1666
Eric Snow7f8bfc92018-01-29 18:23:44 -07001667struct _channelid_xid {
1668 int64_t id;
1669 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001670 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001671};
1672
1673static PyObject *
1674_channelid_from_xid(_PyCrossInterpreterData *data)
1675{
1676 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001677 // Note that we do not preserve the "resolve" flag.
1678 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1679 _global_channels(), 0, 0);
1680 if (xid->end == 0) {
1681 return cid;
1682 }
1683 if (!xid->resolve) {
1684 return cid;
1685 }
1686
1687 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06001688 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04001689 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001690 PyErr_Clear();
1691 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04001692 }
1693 Py_DECREF(cid);
1694 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001695}
1696
1697static int
1698_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1699{
1700 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1701 if (xid == NULL) {
1702 return -1;
1703 }
1704 xid->id = ((channelid *)obj)->id;
1705 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001706 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001707
1708 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06001709 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001710 data->obj = obj;
1711 data->new_object = _channelid_from_xid;
1712 data->free = PyMem_Free;
1713 return 0;
1714}
1715
1716static PyObject *
1717channelid_end(PyObject *self, void *end)
1718{
1719 int force = 1;
1720 channelid *cid = (channelid *)self;
1721 if (end != NULL) {
1722 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001723 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001724 }
1725
1726 if (cid->end == CHANNEL_SEND) {
1727 return PyUnicode_InternFromString("send");
1728 }
1729 if (cid->end == CHANNEL_RECV) {
1730 return PyUnicode_InternFromString("recv");
1731 }
1732 return PyUnicode_InternFromString("both");
1733}
1734
1735static int _channelid_end_send = CHANNEL_SEND;
1736static int _channelid_end_recv = CHANNEL_RECV;
1737
1738static PyGetSetDef channelid_getsets[] = {
1739 {"end", (getter)channelid_end, NULL,
1740 PyDoc_STR("'send', 'recv', or 'both'")},
1741 {"send", (getter)channelid_end, NULL,
1742 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1743 {"recv", (getter)channelid_end, NULL,
1744 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1745 {NULL}
1746};
1747
1748PyDoc_STRVAR(channelid_doc,
1749"A channel ID identifies a channel and may be used as an int.");
1750
1751static PyTypeObject ChannelIDtype = {
1752 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1753 "_xxsubinterpreters.ChannelID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02001754 sizeof(channelid), /* tp_basicsize */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001755 0, /* tp_itemsize */
1756 (destructor)channelid_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001757 0, /* tp_vectorcall_offset */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001758 0, /* tp_getattr */
1759 0, /* tp_setattr */
1760 0, /* tp_as_async */
1761 (reprfunc)channelid_repr, /* tp_repr */
1762 &channelid_as_number, /* tp_as_number */
1763 0, /* tp_as_sequence */
1764 0, /* tp_as_mapping */
1765 channelid_hash, /* tp_hash */
1766 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001767 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001768 0, /* tp_getattro */
1769 0, /* tp_setattro */
1770 0, /* tp_as_buffer */
Serhiy Storchakabf169912019-09-13 22:50:27 +03001771 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001772 channelid_doc, /* tp_doc */
1773 0, /* tp_traverse */
1774 0, /* tp_clear */
1775 channelid_richcompare, /* tp_richcompare */
1776 0, /* tp_weaklistoffset */
1777 0, /* tp_iter */
1778 0, /* tp_iternext */
1779 0, /* tp_methods */
1780 0, /* tp_members */
1781 channelid_getsets, /* tp_getset */
1782 0, /* tp_base */
1783 0, /* tp_dict */
1784 0, /* tp_descr_get */
1785 0, /* tp_descr_set */
1786 0, /* tp_dictoffset */
1787 0, /* tp_init */
1788 0, /* tp_alloc */
1789 // Note that we do not set tp_new to channelid_new. Instead we
1790 // set it to NULL, meaning it cannot be instantiated from Python
1791 // code. We do this because there is a strong relationship between
1792 // channel IDs and the channel lifecycle, so this limitation avoids
1793 // related complications.
1794 NULL, /* tp_new */
1795};
1796
Eric Snow4e9da0d2018-02-02 21:49:49 -07001797
1798/* interpreter-specific code ************************************************/
1799
1800static PyObject * RunFailedError = NULL;
1801
1802static int
1803interp_exceptions_init(PyObject *ns)
1804{
1805 // XXX Move the exceptions into per-module memory?
1806
1807 if (RunFailedError == NULL) {
1808 // An uncaught exception came out of interp_run_string().
1809 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1810 PyExc_RuntimeError, NULL);
1811 if (RunFailedError == NULL) {
1812 return -1;
1813 }
1814 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1815 return -1;
1816 }
1817 }
1818
1819 return 0;
1820}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001821
Eric Snow7f8bfc92018-01-29 18:23:44 -07001822static int
1823_is_running(PyInterpreterState *interp)
1824{
1825 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1826 if (PyThreadState_Next(tstate) != NULL) {
1827 PyErr_SetString(PyExc_RuntimeError,
1828 "interpreter has more than one thread");
1829 return -1;
1830 }
1831 PyFrameObject *frame = tstate->frame;
1832 if (frame == NULL) {
1833 if (PyErr_Occurred() != NULL) {
1834 return -1;
1835 }
1836 return 0;
1837 }
1838 return (int)(frame->f_executing);
1839}
1840
1841static int
1842_ensure_not_running(PyInterpreterState *interp)
1843{
1844 int is_running = _is_running(interp);
1845 if (is_running < 0) {
1846 return -1;
1847 }
1848 if (is_running) {
1849 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1850 return -1;
1851 }
1852 return 0;
1853}
1854
1855static int
1856_run_script(PyInterpreterState *interp, const char *codestr,
Eric Snow4e9da0d2018-02-02 21:49:49 -07001857 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001858{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001859 PyObject *exctype = NULL;
1860 PyObject *excval = NULL;
1861 PyObject *tb = NULL;
1862
Eric Snowc11183c2019-03-15 16:35:46 -06001863 PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001864 if (main_mod == NULL) {
1865 goto error;
1866 }
1867 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1868 Py_DECREF(main_mod);
1869 if (ns == NULL) {
1870 goto error;
1871 }
1872 Py_INCREF(ns);
1873
1874 // Apply the cross-interpreter data.
1875 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001876 if (_sharedns_apply(shared, ns) != 0) {
1877 Py_DECREF(ns);
1878 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001879 }
1880 }
1881
1882 // Run the string (see PyRun_SimpleStringFlags).
1883 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1884 Py_DECREF(ns);
1885 if (result == NULL) {
1886 goto error;
1887 }
1888 else {
1889 Py_DECREF(result); // We throw away the result.
1890 }
1891
Eric Snow4e9da0d2018-02-02 21:49:49 -07001892 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001893 return 0;
1894
1895error:
Eric Snow4e9da0d2018-02-02 21:49:49 -07001896 PyErr_Fetch(&exctype, &excval, &tb);
1897
1898 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1899 Py_XDECREF(exctype);
1900 Py_XDECREF(excval);
1901 Py_XDECREF(tb);
1902 if (sharedexc == NULL) {
1903 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1904 PyErr_Clear();
1905 sharedexc = NULL;
1906 }
1907 else {
1908 assert(!PyErr_Occurred());
1909 }
1910 *exc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001911 return -1;
1912}
1913
1914static int
1915_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1916 PyObject *shareables)
1917{
1918 if (_ensure_not_running(interp) < 0) {
1919 return -1;
1920 }
1921
Eric Snow4e9da0d2018-02-02 21:49:49 -07001922 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001923 if (shared == NULL && PyErr_Occurred()) {
1924 return -1;
1925 }
1926
1927 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001928 PyThreadState *save_tstate = NULL;
Victor Stinnercaba55b2018-08-03 15:33:52 +02001929 if (interp != _PyInterpreterState_Get()) {
Eric Snowf53d9f22018-02-20 16:30:17 -07001930 // XXX Using the "head" thread isn't strictly correct.
1931 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1932 // XXX Possible GILState issues?
1933 save_tstate = PyThreadState_Swap(tstate);
1934 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001935
1936 // Run the script.
1937 _sharedexception *exc = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001938 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001939
1940 // Switch back.
1941 if (save_tstate != NULL) {
1942 PyThreadState_Swap(save_tstate);
1943 }
1944
1945 // Propagate any exception out to the caller.
1946 if (exc != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001947 _sharedexception_apply(exc, RunFailedError);
1948 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001949 }
1950 else if (result != 0) {
1951 // We were unable to allocate a shared exception.
1952 PyErr_NoMemory();
1953 }
1954
1955 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001956 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001957 }
1958
1959 return result;
1960}
1961
1962
1963/* module level code ********************************************************/
1964
1965/* globals is the process-global state for the module. It holds all
1966 the data that we need to share between interpreters, so it cannot
1967 hold PyObject values. */
1968static struct globals {
1969 _channels channels;
1970} _globals = {{0}};
1971
1972static int
1973_init_globals(void)
1974{
1975 if (_channels_init(&_globals.channels) != 0) {
1976 return -1;
1977 }
1978 return 0;
1979}
1980
1981static _channels *
1982_global_channels(void) {
1983 return &_globals.channels;
1984}
1985
1986static PyObject *
1987interp_create(PyObject *self, PyObject *args)
1988{
1989 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
1990 return NULL;
1991 }
1992
1993 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001994 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
1995 // XXX Possible GILState issues?
1996 PyThreadState *tstate = Py_NewInterpreter();
Eric Snow7f8bfc92018-01-29 18:23:44 -07001997 PyThreadState_Swap(save_tstate);
1998 if (tstate == NULL) {
1999 /* Since no new thread state was created, there is no exception to
2000 propagate; raise a fresh one after swapping in the old thread
2001 state. */
2002 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2003 return NULL;
2004 }
Eric Snowc11183c2019-03-15 16:35:46 -06002005 PyObject *idobj = _PyInterpreterState_GetIDObject(tstate->interp);
2006 if (idobj == NULL) {
2007 // XXX Possible GILState issues?
2008 save_tstate = PyThreadState_Swap(tstate);
2009 Py_EndInterpreter(tstate);
2010 PyThreadState_Swap(save_tstate);
2011 return NULL;
2012 }
2013 _PyInterpreterState_RequireIDRef(tstate->interp, 1);
2014 return idobj;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002015}
2016
2017PyDoc_STRVAR(create_doc,
2018"create() -> ID\n\
2019\n\
2020Create a new interpreter and return a unique generated ID.");
2021
2022
2023static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002024interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002025{
Eric Snow6d2cd902018-05-16 15:04:57 -04002026 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002027 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002028 // XXX Use "L" for id?
2029 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2030 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002031 return NULL;
2032 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002033
2034 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06002035 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002036 if (interp == NULL) {
2037 return NULL;
2038 }
2039
2040 // Ensure we don't try to destroy the current interpreter.
2041 PyInterpreterState *current = _get_current();
2042 if (current == NULL) {
2043 return NULL;
2044 }
2045 if (interp == current) {
2046 PyErr_SetString(PyExc_RuntimeError,
2047 "cannot destroy the current interpreter");
2048 return NULL;
2049 }
2050
2051 // Ensure the interpreter isn't running.
2052 /* XXX We *could* support destroying a running interpreter but
2053 aren't going to worry about it for now. */
2054 if (_ensure_not_running(interp) < 0) {
2055 return NULL;
2056 }
2057
2058 // Destroy the interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002059 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2060 // XXX Possible GILState issues?
2061 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002062 Py_EndInterpreter(tstate);
2063 PyThreadState_Swap(save_tstate);
2064
2065 Py_RETURN_NONE;
2066}
2067
2068PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002069"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002070\n\
2071Destroy the identified interpreter.\n\
2072\n\
2073Attempting to destroy the current interpreter results in a RuntimeError.\n\
2074So does an unrecognized ID.");
2075
2076
2077static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302078interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002079{
2080 PyObject *ids, *id;
2081 PyInterpreterState *interp;
2082
2083 ids = PyList_New(0);
2084 if (ids == NULL) {
2085 return NULL;
2086 }
2087
2088 interp = PyInterpreterState_Head();
2089 while (interp != NULL) {
Eric Snowc11183c2019-03-15 16:35:46 -06002090 id = _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002091 if (id == NULL) {
2092 Py_DECREF(ids);
2093 return NULL;
2094 }
2095 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002096 int res = PyList_Insert(ids, 0, id);
2097 Py_DECREF(id);
2098 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002099 Py_DECREF(ids);
2100 return NULL;
2101 }
2102
2103 interp = PyInterpreterState_Next(interp);
2104 }
2105
2106 return ids;
2107}
2108
2109PyDoc_STRVAR(list_all_doc,
2110"list_all() -> [ID]\n\
2111\n\
2112Return a list containing the ID of every existing interpreter.");
2113
2114
2115static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302116interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002117{
2118 PyInterpreterState *interp =_get_current();
2119 if (interp == NULL) {
2120 return NULL;
2121 }
Eric Snowc11183c2019-03-15 16:35:46 -06002122 return _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002123}
2124
2125PyDoc_STRVAR(get_current_doc,
2126"get_current() -> ID\n\
2127\n\
2128Return the ID of current interpreter.");
2129
2130
2131static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302132interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002133{
2134 // Currently, 0 is always the main interpreter.
Eric Snow6d2cd902018-05-16 15:04:57 -04002135 PY_INT64_T id = 0;
Eric Snowc11183c2019-03-15 16:35:46 -06002136 return _PyInterpreterID_New(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002137}
2138
2139PyDoc_STRVAR(get_main_doc,
2140"get_main() -> ID\n\
2141\n\
2142Return the ID of main interpreter.");
2143
2144
2145static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002146interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002147{
Eric Snow6d2cd902018-05-16 15:04:57 -04002148 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002149 PyObject *id, *code;
2150 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002151 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2152 "OU|O:run_string", kwlist,
2153 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002154 return NULL;
2155 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002156
2157 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06002158 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002159 if (interp == NULL) {
2160 return NULL;
2161 }
2162
2163 // Extract code.
2164 Py_ssize_t size;
2165 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2166 if (codestr == NULL) {
2167 return NULL;
2168 }
2169 if (strlen(codestr) != (size_t)size) {
2170 PyErr_SetString(PyExc_ValueError,
2171 "source code string cannot contain null bytes");
2172 return NULL;
2173 }
2174
2175 // Run the code in the interpreter.
2176 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2177 return NULL;
2178 }
2179 Py_RETURN_NONE;
2180}
2181
2182PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002183"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002184\n\
2185Execute the provided string in the identified interpreter.\n\
2186\n\
2187See PyRun_SimpleStrings.");
2188
2189
2190static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002191object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002192{
Eric Snow6d2cd902018-05-16 15:04:57 -04002193 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002194 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002195 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2196 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002197 return NULL;
2198 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002199
Eric Snow7f8bfc92018-01-29 18:23:44 -07002200 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2201 Py_RETURN_TRUE;
2202 }
2203 PyErr_Clear();
2204 Py_RETURN_FALSE;
2205}
2206
2207PyDoc_STRVAR(is_shareable_doc,
2208"is_shareable(obj) -> bool\n\
2209\n\
2210Return True if the object's data may be shared between interpreters and\n\
2211False otherwise.");
2212
2213
2214static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002215interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002216{
Eric Snow6d2cd902018-05-16 15:04:57 -04002217 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002218 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002219 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2220 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002221 return NULL;
2222 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002223
Eric Snowc11183c2019-03-15 16:35:46 -06002224 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002225 if (interp == NULL) {
2226 return NULL;
2227 }
2228 int is_running = _is_running(interp);
2229 if (is_running < 0) {
2230 return NULL;
2231 }
2232 if (is_running) {
2233 Py_RETURN_TRUE;
2234 }
2235 Py_RETURN_FALSE;
2236}
2237
2238PyDoc_STRVAR(is_running_doc,
2239"is_running(id) -> bool\n\
2240\n\
2241Return whether or not the identified interpreter is running.");
2242
2243static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302244channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002245{
2246 int64_t cid = _channel_create(&_globals.channels);
2247 if (cid < 0) {
2248 return NULL;
2249 }
2250 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002251 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002252 if (id == NULL) {
2253 if (_channel_destroy(&_globals.channels, cid) != 0) {
2254 // XXX issue a warning?
2255 }
2256 return NULL;
2257 }
2258 assert(((channelid *)id)->channels != NULL);
2259 return id;
2260}
2261
2262PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002263"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002264\n\
2265Create a new cross-interpreter channel and return a unique generated ID.");
2266
2267static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002268channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002269{
Eric Snow6d2cd902018-05-16 15:04:57 -04002270 static char *kwlist[] = {"cid", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002271 int64_t cid;
2272 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_destroy", kwlist,
2273 channel_id_converter, &cid)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002274 return NULL;
2275 }
2276
2277 if (_channel_destroy(&_globals.channels, cid) != 0) {
2278 return NULL;
2279 }
2280 Py_RETURN_NONE;
2281}
2282
2283PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002284"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002285\n\
2286Close and finalize the channel. Afterward attempts to use the channel\n\
2287will behave as though it never existed.");
2288
2289static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302290channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002291{
2292 int64_t count = 0;
2293 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2294 if (cids == NULL) {
2295 if (count == 0) {
2296 return PyList_New(0);
2297 }
2298 return NULL;
2299 }
2300 PyObject *ids = PyList_New((Py_ssize_t)count);
2301 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002302 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002303 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002304 int64_t *cur = cids;
2305 for (int64_t i=0; i < count; cur++, i++) {
2306 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002307 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002308 if (id == NULL) {
2309 Py_DECREF(ids);
2310 ids = NULL;
2311 break;
2312 }
2313 PyList_SET_ITEM(ids, i, id);
2314 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002315
2316finally:
2317 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002318 return ids;
2319}
2320
2321PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002322"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002323\n\
2324Return the list of all IDs for active channels.");
2325
2326static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002327channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002328{
Eric Snow6d2cd902018-05-16 15:04:57 -04002329 static char *kwlist[] = {"cid", "obj", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002330 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002331 PyObject *obj;
Serhiy Storchakabf169912019-09-13 22:50:27 +03002332 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O:channel_send", kwlist,
2333 channel_id_converter, &cid, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002334 return NULL;
2335 }
2336
2337 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2338 return NULL;
2339 }
2340 Py_RETURN_NONE;
2341}
2342
2343PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002344"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002345\n\
2346Add the object's data to the channel's queue.");
2347
2348static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002349channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002350{
Eric Snow6d2cd902018-05-16 15:04:57 -04002351 static char *kwlist[] = {"cid", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002352 int64_t cid;
2353 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_recv", kwlist,
2354 channel_id_converter, &cid)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002355 return NULL;
2356 }
2357
2358 return _channel_recv(&_globals.channels, cid);
2359}
2360
2361PyDoc_STRVAR(channel_recv_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002362"channel_recv(cid) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002363\n\
2364Return a new object from the data at the from of the channel's queue.");
2365
2366static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002367channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002368{
Eric Snow6d2cd902018-05-16 15:04:57 -04002369 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002370 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04002371 int send = 0;
2372 int recv = 0;
2373 int force = 0;
2374 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03002375 "O&|$ppp:channel_close", kwlist,
2376 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002377 return NULL;
2378 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002379
Eric Snow3ab01362018-05-17 10:27:09 -04002380 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002381 return NULL;
2382 }
2383 Py_RETURN_NONE;
2384}
2385
2386PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002387"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002388\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002389Close the channel for all interpreters.\n\
2390\n\
2391If the channel is empty then the keyword args are ignored and both\n\
2392ends are immediately closed. Otherwise, if 'force' is True then\n\
2393all queued items are released and both ends are immediately\n\
2394closed.\n\
2395\n\
2396If the channel is not empty *and* 'force' is False then following\n\
2397happens:\n\
2398\n\
2399 * recv is True (regardless of send):\n\
2400 - raise ChannelNotEmptyError\n\
2401 * recv is None and send is None:\n\
2402 - raise ChannelNotEmptyError\n\
2403 * send is True and recv is not True:\n\
2404 - fully close the 'send' end\n\
2405 - close the 'recv' end to interpreters not already receiving\n\
2406 - fully close it once empty\n\
2407\n\
2408Closing an already closed channel results in a ChannelClosedError.\n\
2409\n\
2410Once the channel's ID has no more ref counts in any interpreter\n\
2411the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002412
2413static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002414channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002415{
2416 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002417 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002418 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04002419 int send = 0;
2420 int recv = 0;
2421 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002422 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03002423 "O&|$ppp:channel_release", kwlist,
2424 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002425 return NULL;
2426 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002427 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002428 send = 1;
2429 recv = 1;
2430 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002431
2432 // XXX Handle force is True.
2433 // XXX Fix implicit release.
2434
Eric Snow7f8bfc92018-01-29 18:23:44 -07002435 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2436 return NULL;
2437 }
2438 Py_RETURN_NONE;
2439}
2440
Eric Snow6d2cd902018-05-16 15:04:57 -04002441PyDoc_STRVAR(channel_release_doc,
2442"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002443\n\
2444Close the channel for the current interpreter. 'send' and 'recv'\n\
2445(bool) may be used to indicate the ends to close. By default both\n\
2446ends are closed. Closing an already closed end is a noop.");
2447
2448static PyObject *
2449channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2450{
2451 return channelid_new(&ChannelIDtype, args, kwds);
2452}
2453
2454static PyMethodDef module_functions[] = {
2455 {"create", (PyCFunction)interp_create,
2456 METH_VARARGS, create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002457 {"destroy", (PyCFunction)(void(*)(void))interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002458 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302459 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002460 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302461 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002462 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302463 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002464 METH_NOARGS, get_main_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002465 {"is_running", (PyCFunction)(void(*)(void))interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002466 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002467 {"run_string", (PyCFunction)(void(*)(void))interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002468 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002469
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002470 {"is_shareable", (PyCFunction)(void(*)(void))object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002471 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002472
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302473 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002474 METH_NOARGS, channel_create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002475 {"channel_destroy", (PyCFunction)(void(*)(void))channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002476 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302477 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002478 METH_NOARGS, channel_list_all_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002479 {"channel_send", (PyCFunction)(void(*)(void))channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002480 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002481 {"channel_recv", (PyCFunction)(void(*)(void))channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002482 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002483 {"channel_close", (PyCFunction)(void(*)(void))channel_close,
Eric Snow6d2cd902018-05-16 15:04:57 -04002484 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002485 {"channel_release", (PyCFunction)(void(*)(void))channel_release,
Eric Snow6d2cd902018-05-16 15:04:57 -04002486 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002487 {"_channel_id", (PyCFunction)(void(*)(void))channel__channel_id,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002488 METH_VARARGS | METH_KEYWORDS, NULL},
2489
2490 {NULL, NULL} /* sentinel */
2491};
2492
2493
2494/* initialization function */
2495
2496PyDoc_STRVAR(module_doc,
2497"This module provides primitive operations to manage Python interpreters.\n\
2498The 'interpreters' module provides a more convenient interface.");
2499
2500static struct PyModuleDef interpretersmodule = {
2501 PyModuleDef_HEAD_INIT,
2502 "_xxsubinterpreters", /* m_name */
2503 module_doc, /* m_doc */
2504 -1, /* m_size */
2505 module_functions, /* m_methods */
2506 NULL, /* m_slots */
2507 NULL, /* m_traverse */
2508 NULL, /* m_clear */
2509 NULL /* m_free */
2510};
2511
2512
2513PyMODINIT_FUNC
2514PyInit__xxsubinterpreters(void)
2515{
2516 if (_init_globals() != 0) {
2517 return NULL;
2518 }
2519
2520 /* Initialize types */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002521 if (PyType_Ready(&ChannelIDtype) != 0) {
2522 return NULL;
2523 }
2524
2525 /* Create the module */
2526 PyObject *module = PyModule_Create(&interpretersmodule);
2527 if (module == NULL) {
2528 return NULL;
2529 }
2530
2531 /* Add exception types */
2532 PyObject *ns = PyModule_GetDict(module); // borrowed
2533 if (interp_exceptions_init(ns) != 0) {
2534 return NULL;
2535 }
2536 if (channel_exceptions_init(ns) != 0) {
2537 return NULL;
2538 }
2539
2540 /* Add other types */
2541 Py_INCREF(&ChannelIDtype);
2542 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2543 return NULL;
2544 }
Eric Snowc11183c2019-03-15 16:35:46 -06002545 Py_INCREF(&_PyInterpreterID_Type);
2546 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&_PyInterpreterID_Type) != 0) {
Eric Snow4c6955e2018-02-16 18:53:40 -07002547 return NULL;
2548 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002549
Eric Snowc11183c2019-03-15 16:35:46 -06002550 if (_PyCrossInterpreterData_RegisterClass(&ChannelIDtype, _channelid_shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002551 return NULL;
2552 }
2553
2554 return module;
2555}