blob: 1cf43b7ac76e04880ae1bd92f5ffde8020dc6e7f [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 Snowbcfa4502019-03-01 16:50:31 -07007#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 Snowbcfa4502019-03-01 16:50:31 -070042static 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 Snowbcfa4502019-03-01 16:50:31 -070052 _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 Snowbcfa4502019-03-01 16:50:31 -070063 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);
1253};
1254
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) {
1314 PyThread_release_lock(mutex);
Eric Snowbcfa4502019-03-01 16:50:31 -07001315 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001316 return -1;
1317 }
1318
1319 // Add the data to the channel.
Eric Snowbcfa4502019-03-01 16:50:31 -07001320 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 Snowbcfa4502019-03-01 16:50:31 -07001348 _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 Snowbcfa4502019-03-01 16:50:31 -07001385 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
1408static channelid *
1409newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001410 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001411{
1412 channelid *self = PyObject_New(channelid, cls);
1413 if (self == NULL) {
1414 return NULL;
1415 }
1416 self->id = cid;
1417 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001418 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001419 self->channels = channels;
1420
1421 if (_channels_add_id_object(channels, cid) != 0) {
1422 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1423 PyErr_Clear();
1424 }
1425 else {
1426 Py_DECREF((PyObject *)self);
1427 return NULL;
1428 }
1429 }
1430
1431 return self;
1432}
1433
1434static _channels * _global_channels(void);
1435
1436static PyObject *
1437channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1438{
Eric Snow6d2cd902018-05-16 15:04:57 -04001439 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07001440 PyObject *id;
1441 int send = -1;
1442 int recv = -1;
1443 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001444 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001445 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04001446 "O|$pppp:ChannelID.__new__", kwlist,
1447 &id, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001448 return NULL;
1449
1450 // Coerce and check the ID.
1451 int64_t cid;
1452 if (PyObject_TypeCheck(id, &ChannelIDtype)) {
1453 cid = ((channelid *)id)->id;
1454 }
1455 else {
Eric Snowbcfa4502019-03-01 16:50:31 -07001456 cid = _Py_CoerceID(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001457 if (cid < 0) {
1458 return NULL;
1459 }
1460 }
1461
1462 // Handle "send" and "recv".
1463 if (send == 0 && recv == 0) {
1464 PyErr_SetString(PyExc_ValueError,
1465 "'send' and 'recv' cannot both be False");
1466 return NULL;
1467 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001468
Eric Snow7f8bfc92018-01-29 18:23:44 -07001469 int end = 0;
1470 if (send == 1) {
1471 if (recv == 0 || recv == -1) {
1472 end = CHANNEL_SEND;
1473 }
1474 }
1475 else if (recv == 1) {
1476 end = CHANNEL_RECV;
1477 }
1478
Eric Snow6d2cd902018-05-16 15:04:57 -04001479 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
1480 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001481}
1482
1483static void
1484channelid_dealloc(PyObject *v)
1485{
1486 int64_t cid = ((channelid *)v)->id;
1487 _channels *channels = ((channelid *)v)->channels;
1488 Py_TYPE(v)->tp_free(v);
1489
1490 _channels_drop_id_object(channels, cid);
1491}
1492
1493static PyObject *
1494channelid_repr(PyObject *self)
1495{
1496 PyTypeObject *type = Py_TYPE(self);
1497 const char *name = _PyType_Name(type);
1498
1499 channelid *cid = (channelid *)self;
1500 const char *fmt;
1501 if (cid->end == CHANNEL_SEND) {
Eric Snowab4a1982018-06-13 08:02:39 -06001502 fmt = "%s(%" PRId64 ", send=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001503 }
1504 else if (cid->end == CHANNEL_RECV) {
Eric Snowab4a1982018-06-13 08:02:39 -06001505 fmt = "%s(%" PRId64 ", recv=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001506 }
1507 else {
Eric Snowab4a1982018-06-13 08:02:39 -06001508 fmt = "%s(%" PRId64 ")";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001509 }
1510 return PyUnicode_FromFormat(fmt, name, cid->id);
1511}
1512
Eric Snow6d2cd902018-05-16 15:04:57 -04001513static PyObject *
1514channelid_str(PyObject *self)
1515{
1516 channelid *cid = (channelid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06001517 return PyUnicode_FromFormat("%" PRId64 "", cid->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001518}
1519
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001520static PyObject *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001521channelid_int(PyObject *self)
1522{
1523 channelid *cid = (channelid *)self;
1524 return PyLong_FromLongLong(cid->id);
1525}
1526
1527static PyNumberMethods channelid_as_number = {
1528 0, /* nb_add */
1529 0, /* nb_subtract */
1530 0, /* nb_multiply */
1531 0, /* nb_remainder */
1532 0, /* nb_divmod */
1533 0, /* nb_power */
1534 0, /* nb_negative */
1535 0, /* nb_positive */
1536 0, /* nb_absolute */
1537 0, /* nb_bool */
1538 0, /* nb_invert */
1539 0, /* nb_lshift */
1540 0, /* nb_rshift */
1541 0, /* nb_and */
1542 0, /* nb_xor */
1543 0, /* nb_or */
1544 (unaryfunc)channelid_int, /* nb_int */
1545 0, /* nb_reserved */
1546 0, /* nb_float */
1547
1548 0, /* nb_inplace_add */
1549 0, /* nb_inplace_subtract */
1550 0, /* nb_inplace_multiply */
1551 0, /* nb_inplace_remainder */
1552 0, /* nb_inplace_power */
1553 0, /* nb_inplace_lshift */
1554 0, /* nb_inplace_rshift */
1555 0, /* nb_inplace_and */
1556 0, /* nb_inplace_xor */
1557 0, /* nb_inplace_or */
1558
1559 0, /* nb_floor_divide */
1560 0, /* nb_true_divide */
1561 0, /* nb_inplace_floor_divide */
1562 0, /* nb_inplace_true_divide */
1563
1564 (unaryfunc)channelid_int, /* nb_index */
1565};
1566
1567static Py_hash_t
1568channelid_hash(PyObject *self)
1569{
1570 channelid *cid = (channelid *)self;
1571 PyObject *id = PyLong_FromLongLong(cid->id);
1572 if (id == NULL) {
1573 return -1;
1574 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001575 Py_hash_t hash = PyObject_Hash(id);
1576 Py_DECREF(id);
1577 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001578}
1579
1580static PyObject *
1581channelid_richcompare(PyObject *self, PyObject *other, int op)
1582{
1583 if (op != Py_EQ && op != Py_NE) {
1584 Py_RETURN_NOTIMPLEMENTED;
1585 }
1586
1587 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1588 Py_RETURN_NOTIMPLEMENTED;
1589 }
1590
1591 channelid *cid = (channelid *)self;
1592 int equal;
1593 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1594 channelid *othercid = (channelid *)other;
1595 if (cid->end != othercid->end) {
1596 equal = 0;
1597 }
1598 else {
1599 equal = (cid->id == othercid->id);
1600 }
1601 }
1602 else {
1603 other = PyNumber_Long(other);
1604 if (other == NULL) {
1605 PyErr_Clear();
1606 Py_RETURN_NOTIMPLEMENTED;
1607 }
1608 int64_t othercid = PyLong_AsLongLong(other);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001609 Py_DECREF(other);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001610 if (othercid == -1 && PyErr_Occurred() != NULL) {
1611 return NULL;
1612 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001613 if (othercid < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001614 equal = 0;
1615 }
1616 else {
1617 equal = (cid->id == othercid);
1618 }
1619 }
1620
1621 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1622 Py_RETURN_TRUE;
1623 }
1624 Py_RETURN_FALSE;
1625}
1626
Eric Snowab4a1982018-06-13 08:02:39 -06001627static PyObject *
1628_channel_from_cid(PyObject *cid, int end)
1629{
1630 PyObject *highlevel = PyImport_ImportModule("interpreters");
1631 if (highlevel == NULL) {
1632 PyErr_Clear();
1633 highlevel = PyImport_ImportModule("test.support.interpreters");
1634 if (highlevel == NULL) {
1635 return NULL;
1636 }
1637 }
1638 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
1639 "SendChannel";
1640 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1641 Py_DECREF(highlevel);
1642 if (cls == NULL) {
1643 return NULL;
1644 }
1645 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1646 Py_DECREF(cls);
1647 if (chan == NULL) {
1648 return NULL;
1649 }
1650 return chan;
1651}
1652
Eric Snow7f8bfc92018-01-29 18:23:44 -07001653struct _channelid_xid {
1654 int64_t id;
1655 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001656 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001657};
1658
1659static PyObject *
1660_channelid_from_xid(_PyCrossInterpreterData *data)
1661{
1662 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001663 // Note that we do not preserve the "resolve" flag.
1664 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1665 _global_channels(), 0, 0);
1666 if (xid->end == 0) {
1667 return cid;
1668 }
1669 if (!xid->resolve) {
1670 return cid;
1671 }
1672
1673 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06001674 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04001675 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001676 PyErr_Clear();
1677 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04001678 }
1679 Py_DECREF(cid);
1680 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001681}
1682
1683static int
1684_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1685{
1686 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1687 if (xid == NULL) {
1688 return -1;
1689 }
1690 xid->id = ((channelid *)obj)->id;
1691 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001692 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001693
1694 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06001695 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001696 data->obj = obj;
1697 data->new_object = _channelid_from_xid;
1698 data->free = PyMem_Free;
1699 return 0;
1700}
1701
1702static PyObject *
1703channelid_end(PyObject *self, void *end)
1704{
1705 int force = 1;
1706 channelid *cid = (channelid *)self;
1707 if (end != NULL) {
1708 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001709 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001710 }
1711
1712 if (cid->end == CHANNEL_SEND) {
1713 return PyUnicode_InternFromString("send");
1714 }
1715 if (cid->end == CHANNEL_RECV) {
1716 return PyUnicode_InternFromString("recv");
1717 }
1718 return PyUnicode_InternFromString("both");
1719}
1720
1721static int _channelid_end_send = CHANNEL_SEND;
1722static int _channelid_end_recv = CHANNEL_RECV;
1723
1724static PyGetSetDef channelid_getsets[] = {
1725 {"end", (getter)channelid_end, NULL,
1726 PyDoc_STR("'send', 'recv', or 'both'")},
1727 {"send", (getter)channelid_end, NULL,
1728 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1729 {"recv", (getter)channelid_end, NULL,
1730 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1731 {NULL}
1732};
1733
1734PyDoc_STRVAR(channelid_doc,
1735"A channel ID identifies a channel and may be used as an int.");
1736
1737static PyTypeObject ChannelIDtype = {
1738 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1739 "_xxsubinterpreters.ChannelID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02001740 sizeof(channelid), /* tp_basicsize */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001741 0, /* tp_itemsize */
1742 (destructor)channelid_dealloc, /* tp_dealloc */
1743 0, /* tp_print */
1744 0, /* tp_getattr */
1745 0, /* tp_setattr */
1746 0, /* tp_as_async */
1747 (reprfunc)channelid_repr, /* tp_repr */
1748 &channelid_as_number, /* tp_as_number */
1749 0, /* tp_as_sequence */
1750 0, /* tp_as_mapping */
1751 channelid_hash, /* tp_hash */
1752 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001753 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001754 0, /* tp_getattro */
1755 0, /* tp_setattro */
1756 0, /* tp_as_buffer */
1757 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1758 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
1759 channelid_doc, /* tp_doc */
1760 0, /* tp_traverse */
1761 0, /* tp_clear */
1762 channelid_richcompare, /* tp_richcompare */
1763 0, /* tp_weaklistoffset */
1764 0, /* tp_iter */
1765 0, /* tp_iternext */
1766 0, /* tp_methods */
1767 0, /* tp_members */
1768 channelid_getsets, /* tp_getset */
1769 0, /* tp_base */
1770 0, /* tp_dict */
1771 0, /* tp_descr_get */
1772 0, /* tp_descr_set */
1773 0, /* tp_dictoffset */
1774 0, /* tp_init */
1775 0, /* tp_alloc */
1776 // Note that we do not set tp_new to channelid_new. Instead we
1777 // set it to NULL, meaning it cannot be instantiated from Python
1778 // code. We do this because there is a strong relationship between
1779 // channel IDs and the channel lifecycle, so this limitation avoids
1780 // related complications.
1781 NULL, /* tp_new */
1782};
1783
Eric Snow4e9da0d2018-02-02 21:49:49 -07001784
1785/* interpreter-specific code ************************************************/
1786
1787static PyObject * RunFailedError = NULL;
1788
1789static int
1790interp_exceptions_init(PyObject *ns)
1791{
1792 // XXX Move the exceptions into per-module memory?
1793
1794 if (RunFailedError == NULL) {
1795 // An uncaught exception came out of interp_run_string().
1796 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1797 PyExc_RuntimeError, NULL);
1798 if (RunFailedError == NULL) {
1799 return -1;
1800 }
1801 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1802 return -1;
1803 }
1804 }
1805
1806 return 0;
1807}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001808
Eric Snow7f8bfc92018-01-29 18:23:44 -07001809static int
1810_is_running(PyInterpreterState *interp)
1811{
1812 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1813 if (PyThreadState_Next(tstate) != NULL) {
1814 PyErr_SetString(PyExc_RuntimeError,
1815 "interpreter has more than one thread");
1816 return -1;
1817 }
1818 PyFrameObject *frame = tstate->frame;
1819 if (frame == NULL) {
1820 if (PyErr_Occurred() != NULL) {
1821 return -1;
1822 }
1823 return 0;
1824 }
1825 return (int)(frame->f_executing);
1826}
1827
1828static int
1829_ensure_not_running(PyInterpreterState *interp)
1830{
1831 int is_running = _is_running(interp);
1832 if (is_running < 0) {
1833 return -1;
1834 }
1835 if (is_running) {
1836 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1837 return -1;
1838 }
1839 return 0;
1840}
1841
1842static int
1843_run_script(PyInterpreterState *interp, const char *codestr,
Eric Snow4e9da0d2018-02-02 21:49:49 -07001844 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001845{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001846 PyObject *exctype = NULL;
1847 PyObject *excval = NULL;
1848 PyObject *tb = NULL;
1849
Eric Snowbcfa4502019-03-01 16:50:31 -07001850 PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001851 if (main_mod == NULL) {
1852 goto error;
1853 }
1854 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1855 Py_DECREF(main_mod);
1856 if (ns == NULL) {
1857 goto error;
1858 }
1859 Py_INCREF(ns);
1860
1861 // Apply the cross-interpreter data.
1862 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001863 if (_sharedns_apply(shared, ns) != 0) {
1864 Py_DECREF(ns);
1865 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001866 }
1867 }
1868
1869 // Run the string (see PyRun_SimpleStringFlags).
1870 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1871 Py_DECREF(ns);
1872 if (result == NULL) {
1873 goto error;
1874 }
1875 else {
1876 Py_DECREF(result); // We throw away the result.
1877 }
1878
Eric Snow4e9da0d2018-02-02 21:49:49 -07001879 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001880 return 0;
1881
1882error:
Eric Snow4e9da0d2018-02-02 21:49:49 -07001883 PyErr_Fetch(&exctype, &excval, &tb);
1884
1885 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1886 Py_XDECREF(exctype);
1887 Py_XDECREF(excval);
1888 Py_XDECREF(tb);
1889 if (sharedexc == NULL) {
1890 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1891 PyErr_Clear();
1892 sharedexc = NULL;
1893 }
1894 else {
1895 assert(!PyErr_Occurred());
1896 }
1897 *exc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001898 return -1;
1899}
1900
1901static int
1902_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1903 PyObject *shareables)
1904{
1905 if (_ensure_not_running(interp) < 0) {
1906 return -1;
1907 }
1908
Eric Snow4e9da0d2018-02-02 21:49:49 -07001909 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001910 if (shared == NULL && PyErr_Occurred()) {
1911 return -1;
1912 }
1913
1914 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001915 PyThreadState *save_tstate = NULL;
Victor Stinnercaba55b2018-08-03 15:33:52 +02001916 if (interp != _PyInterpreterState_Get()) {
Eric Snowf53d9f22018-02-20 16:30:17 -07001917 // XXX Using the "head" thread isn't strictly correct.
1918 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1919 // XXX Possible GILState issues?
1920 save_tstate = PyThreadState_Swap(tstate);
1921 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001922
1923 // Run the script.
1924 _sharedexception *exc = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001925 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001926
1927 // Switch back.
1928 if (save_tstate != NULL) {
1929 PyThreadState_Swap(save_tstate);
1930 }
1931
1932 // Propagate any exception out to the caller.
1933 if (exc != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001934 _sharedexception_apply(exc, RunFailedError);
1935 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001936 }
1937 else if (result != 0) {
1938 // We were unable to allocate a shared exception.
1939 PyErr_NoMemory();
1940 }
1941
1942 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001943 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001944 }
1945
1946 return result;
1947}
1948
1949
1950/* module level code ********************************************************/
1951
1952/* globals is the process-global state for the module. It holds all
1953 the data that we need to share between interpreters, so it cannot
1954 hold PyObject values. */
1955static struct globals {
1956 _channels channels;
1957} _globals = {{0}};
1958
1959static int
1960_init_globals(void)
1961{
1962 if (_channels_init(&_globals.channels) != 0) {
1963 return -1;
1964 }
1965 return 0;
1966}
1967
1968static _channels *
1969_global_channels(void) {
1970 return &_globals.channels;
1971}
1972
1973static PyObject *
1974interp_create(PyObject *self, PyObject *args)
1975{
1976 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
1977 return NULL;
1978 }
1979
1980 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001981 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
1982 // XXX Possible GILState issues?
1983 PyThreadState *tstate = Py_NewInterpreter();
Eric Snow7f8bfc92018-01-29 18:23:44 -07001984 PyThreadState_Swap(save_tstate);
1985 if (tstate == NULL) {
1986 /* Since no new thread state was created, there is no exception to
1987 propagate; raise a fresh one after swapping in the old thread
1988 state. */
1989 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
1990 return NULL;
1991 }
Eric Snowbcfa4502019-03-01 16:50:31 -07001992 PyObject *idobj = _PyInterpreterState_GetIDObject(tstate->interp);
1993 if (idobj == NULL) {
1994 // XXX Possible GILState issues?
1995 save_tstate = PyThreadState_Swap(tstate);
1996 Py_EndInterpreter(tstate);
1997 PyThreadState_Swap(save_tstate);
1998 return NULL;
1999 }
2000 _PyInterpreterState_RequireIDRef(tstate->interp, 1);
2001 return idobj;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002002}
2003
2004PyDoc_STRVAR(create_doc,
2005"create() -> ID\n\
2006\n\
2007Create a new interpreter and return a unique generated ID.");
2008
2009
2010static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002011interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002012{
Eric Snow6d2cd902018-05-16 15:04:57 -04002013 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002014 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002015 // XXX Use "L" for id?
2016 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2017 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002018 return NULL;
2019 }
2020 if (!PyLong_Check(id)) {
2021 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2022 return NULL;
2023 }
2024
2025 // Look up the interpreter.
Eric Snowbcfa4502019-03-01 16:50:31 -07002026 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002027 if (interp == NULL) {
2028 return NULL;
2029 }
2030
2031 // Ensure we don't try to destroy the current interpreter.
2032 PyInterpreterState *current = _get_current();
2033 if (current == NULL) {
2034 return NULL;
2035 }
2036 if (interp == current) {
2037 PyErr_SetString(PyExc_RuntimeError,
2038 "cannot destroy the current interpreter");
2039 return NULL;
2040 }
2041
2042 // Ensure the interpreter isn't running.
2043 /* XXX We *could* support destroying a running interpreter but
2044 aren't going to worry about it for now. */
2045 if (_ensure_not_running(interp) < 0) {
2046 return NULL;
2047 }
2048
2049 // Destroy the interpreter.
2050 //PyInterpreterState_Delete(interp);
Eric Snowf53d9f22018-02-20 16:30:17 -07002051 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2052 // XXX Possible GILState issues?
2053 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002054 Py_EndInterpreter(tstate);
2055 PyThreadState_Swap(save_tstate);
2056
2057 Py_RETURN_NONE;
2058}
2059
2060PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002061"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002062\n\
2063Destroy the identified interpreter.\n\
2064\n\
2065Attempting to destroy the current interpreter results in a RuntimeError.\n\
2066So does an unrecognized ID.");
2067
2068
2069static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302070interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002071{
2072 PyObject *ids, *id;
2073 PyInterpreterState *interp;
2074
2075 ids = PyList_New(0);
2076 if (ids == NULL) {
2077 return NULL;
2078 }
2079
2080 interp = PyInterpreterState_Head();
2081 while (interp != NULL) {
Eric Snowbcfa4502019-03-01 16:50:31 -07002082 id = _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002083 if (id == NULL) {
2084 Py_DECREF(ids);
2085 return NULL;
2086 }
2087 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002088 int res = PyList_Insert(ids, 0, id);
2089 Py_DECREF(id);
2090 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002091 Py_DECREF(ids);
2092 return NULL;
2093 }
2094
2095 interp = PyInterpreterState_Next(interp);
2096 }
2097
2098 return ids;
2099}
2100
2101PyDoc_STRVAR(list_all_doc,
2102"list_all() -> [ID]\n\
2103\n\
2104Return a list containing the ID of every existing interpreter.");
2105
2106
2107static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302108interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002109{
2110 PyInterpreterState *interp =_get_current();
2111 if (interp == NULL) {
2112 return NULL;
2113 }
Eric Snowbcfa4502019-03-01 16:50:31 -07002114 return _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002115}
2116
2117PyDoc_STRVAR(get_current_doc,
2118"get_current() -> ID\n\
2119\n\
2120Return the ID of current interpreter.");
2121
2122
2123static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302124interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002125{
2126 // Currently, 0 is always the main interpreter.
Eric Snow6d2cd902018-05-16 15:04:57 -04002127 PY_INT64_T id = 0;
Eric Snowbcfa4502019-03-01 16:50:31 -07002128 return _PyInterpreterID_New(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002129}
2130
2131PyDoc_STRVAR(get_main_doc,
2132"get_main() -> ID\n\
2133\n\
2134Return the ID of main interpreter.");
2135
2136
2137static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002138interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002139{
Eric Snow6d2cd902018-05-16 15:04:57 -04002140 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002141 PyObject *id, *code;
2142 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002143 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2144 "OU|O:run_string", kwlist,
2145 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002146 return NULL;
2147 }
2148 if (!PyLong_Check(id)) {
2149 PyErr_SetString(PyExc_TypeError, "first arg (ID) must be an int");
2150 return NULL;
2151 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002152
2153 // Look up the interpreter.
Eric Snowbcfa4502019-03-01 16:50:31 -07002154 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002155 if (interp == NULL) {
2156 return NULL;
2157 }
2158
2159 // Extract code.
2160 Py_ssize_t size;
2161 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2162 if (codestr == NULL) {
2163 return NULL;
2164 }
2165 if (strlen(codestr) != (size_t)size) {
2166 PyErr_SetString(PyExc_ValueError,
2167 "source code string cannot contain null bytes");
2168 return NULL;
2169 }
2170
2171 // Run the code in the interpreter.
2172 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2173 return NULL;
2174 }
2175 Py_RETURN_NONE;
2176}
2177
2178PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002179"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002180\n\
2181Execute the provided string in the identified interpreter.\n\
2182\n\
2183See PyRun_SimpleStrings.");
2184
2185
2186static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002187object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002188{
Eric Snow6d2cd902018-05-16 15:04:57 -04002189 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002190 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002191 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2192 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002193 return NULL;
2194 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002195
Eric Snow7f8bfc92018-01-29 18:23:44 -07002196 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2197 Py_RETURN_TRUE;
2198 }
2199 PyErr_Clear();
2200 Py_RETURN_FALSE;
2201}
2202
2203PyDoc_STRVAR(is_shareable_doc,
2204"is_shareable(obj) -> bool\n\
2205\n\
2206Return True if the object's data may be shared between interpreters and\n\
2207False otherwise.");
2208
2209
2210static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002211interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002212{
Eric Snow6d2cd902018-05-16 15:04:57 -04002213 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002214 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002215 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2216 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002217 return NULL;
2218 }
2219 if (!PyLong_Check(id)) {
2220 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2221 return NULL;
2222 }
2223
Eric Snowbcfa4502019-03-01 16:50:31 -07002224 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};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002271 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002272 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2273 "O:channel_destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002274 return NULL;
2275 }
Eric Snowbcfa4502019-03-01 16:50:31 -07002276 int64_t cid = _Py_CoerceID(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002277 if (cid < 0) {
2278 return NULL;
2279 }
2280
2281 if (_channel_destroy(&_globals.channels, cid) != 0) {
2282 return NULL;
2283 }
2284 Py_RETURN_NONE;
2285}
2286
2287PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002288"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002289\n\
2290Close and finalize the channel. Afterward attempts to use the channel\n\
2291will behave as though it never existed.");
2292
2293static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302294channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002295{
2296 int64_t count = 0;
2297 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2298 if (cids == NULL) {
2299 if (count == 0) {
2300 return PyList_New(0);
2301 }
2302 return NULL;
2303 }
2304 PyObject *ids = PyList_New((Py_ssize_t)count);
2305 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002306 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002307 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002308 int64_t *cur = cids;
2309 for (int64_t i=0; i < count; cur++, i++) {
2310 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002311 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002312 if (id == NULL) {
2313 Py_DECREF(ids);
2314 ids = NULL;
2315 break;
2316 }
2317 PyList_SET_ITEM(ids, i, id);
2318 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002319
2320finally:
2321 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002322 return ids;
2323}
2324
2325PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002326"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002327\n\
2328Return the list of all IDs for active channels.");
2329
2330static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002331channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002332{
Eric Snow6d2cd902018-05-16 15:04:57 -04002333 static char *kwlist[] = {"cid", "obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002334 PyObject *id;
2335 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002336 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2337 "OO:channel_send", kwlist, &id, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002338 return NULL;
2339 }
Eric Snowbcfa4502019-03-01 16:50:31 -07002340 int64_t cid = _Py_CoerceID(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002341 if (cid < 0) {
2342 return NULL;
2343 }
2344
2345 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2346 return NULL;
2347 }
2348 Py_RETURN_NONE;
2349}
2350
2351PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002352"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002353\n\
2354Add the object's data to the channel's queue.");
2355
2356static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002357channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002358{
Eric Snow6d2cd902018-05-16 15:04:57 -04002359 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002360 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002361 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2362 "O:channel_recv", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002363 return NULL;
2364 }
Eric Snowbcfa4502019-03-01 16:50:31 -07002365 int64_t cid = _Py_CoerceID(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002366 if (cid < 0) {
2367 return NULL;
2368 }
2369
2370 return _channel_recv(&_globals.channels, cid);
2371}
2372
2373PyDoc_STRVAR(channel_recv_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002374"channel_recv(cid) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002375\n\
2376Return a new object from the data at the from of the channel's queue.");
2377
2378static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002379channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002380{
Eric Snow6d2cd902018-05-16 15:04:57 -04002381 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
2382 PyObject *id;
2383 int send = 0;
2384 int recv = 0;
2385 int force = 0;
2386 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2387 "O|$ppp:channel_close", kwlist,
2388 &id, &send, &recv, &force)) {
2389 return NULL;
2390 }
Eric Snowbcfa4502019-03-01 16:50:31 -07002391 int64_t cid = _Py_CoerceID(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002392 if (cid < 0) {
2393 return NULL;
2394 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002395
Eric Snow3ab01362018-05-17 10:27:09 -04002396 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002397 return NULL;
2398 }
2399 Py_RETURN_NONE;
2400}
2401
2402PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002403"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002404\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002405Close the channel for all interpreters.\n\
2406\n\
2407If the channel is empty then the keyword args are ignored and both\n\
2408ends are immediately closed. Otherwise, if 'force' is True then\n\
2409all queued items are released and both ends are immediately\n\
2410closed.\n\
2411\n\
2412If the channel is not empty *and* 'force' is False then following\n\
2413happens:\n\
2414\n\
2415 * recv is True (regardless of send):\n\
2416 - raise ChannelNotEmptyError\n\
2417 * recv is None and send is None:\n\
2418 - raise ChannelNotEmptyError\n\
2419 * send is True and recv is not True:\n\
2420 - fully close the 'send' end\n\
2421 - close the 'recv' end to interpreters not already receiving\n\
2422 - fully close it once empty\n\
2423\n\
2424Closing an already closed channel results in a ChannelClosedError.\n\
2425\n\
2426Once the channel's ID has no more ref counts in any interpreter\n\
2427the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002428
2429static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002430channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002431{
2432 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002433 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002434 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002435 int send = 0;
2436 int recv = 0;
2437 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002438 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04002439 "O|$ppp:channel_release", kwlist,
2440 &id, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002441 return NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002442 }
Eric Snowbcfa4502019-03-01 16:50:31 -07002443 int64_t cid = _Py_CoerceID(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002444 if (cid < 0) {
2445 return NULL;
2446 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002447 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002448 send = 1;
2449 recv = 1;
2450 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002451
2452 // XXX Handle force is True.
2453 // XXX Fix implicit release.
2454
Eric Snow7f8bfc92018-01-29 18:23:44 -07002455 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2456 return NULL;
2457 }
2458 Py_RETURN_NONE;
2459}
2460
Eric Snow6d2cd902018-05-16 15:04:57 -04002461PyDoc_STRVAR(channel_release_doc,
2462"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002463\n\
2464Close the channel for the current interpreter. 'send' and 'recv'\n\
2465(bool) may be used to indicate the ends to close. By default both\n\
2466ends are closed. Closing an already closed end is a noop.");
2467
2468static PyObject *
2469channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2470{
2471 return channelid_new(&ChannelIDtype, args, kwds);
2472}
2473
2474static PyMethodDef module_functions[] = {
2475 {"create", (PyCFunction)interp_create,
2476 METH_VARARGS, create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002477 {"destroy", (PyCFunction)(void(*)(void))interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002478 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302479 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002480 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302481 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002482 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302483 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002484 METH_NOARGS, get_main_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002485 {"is_running", (PyCFunction)(void(*)(void))interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002486 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002487 {"run_string", (PyCFunction)(void(*)(void))interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002488 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002489
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002490 {"is_shareable", (PyCFunction)(void(*)(void))object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002491 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002492
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302493 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002494 METH_NOARGS, channel_create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002495 {"channel_destroy", (PyCFunction)(void(*)(void))channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002496 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302497 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002498 METH_NOARGS, channel_list_all_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002499 {"channel_send", (PyCFunction)(void(*)(void))channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002500 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002501 {"channel_recv", (PyCFunction)(void(*)(void))channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002502 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002503 {"channel_close", (PyCFunction)(void(*)(void))channel_close,
Eric Snow6d2cd902018-05-16 15:04:57 -04002504 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002505 {"channel_release", (PyCFunction)(void(*)(void))channel_release,
Eric Snow6d2cd902018-05-16 15:04:57 -04002506 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002507 {"_channel_id", (PyCFunction)(void(*)(void))channel__channel_id,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002508 METH_VARARGS | METH_KEYWORDS, NULL},
2509
2510 {NULL, NULL} /* sentinel */
2511};
2512
2513
2514/* initialization function */
2515
2516PyDoc_STRVAR(module_doc,
2517"This module provides primitive operations to manage Python interpreters.\n\
2518The 'interpreters' module provides a more convenient interface.");
2519
2520static struct PyModuleDef interpretersmodule = {
2521 PyModuleDef_HEAD_INIT,
2522 "_xxsubinterpreters", /* m_name */
2523 module_doc, /* m_doc */
2524 -1, /* m_size */
2525 module_functions, /* m_methods */
2526 NULL, /* m_slots */
2527 NULL, /* m_traverse */
2528 NULL, /* m_clear */
2529 NULL /* m_free */
2530};
2531
2532
2533PyMODINIT_FUNC
2534PyInit__xxsubinterpreters(void)
2535{
2536 if (_init_globals() != 0) {
2537 return NULL;
2538 }
2539
2540 /* Initialize types */
2541 ChannelIDtype.tp_base = &PyLong_Type;
2542 if (PyType_Ready(&ChannelIDtype) != 0) {
2543 return NULL;
2544 }
2545
2546 /* Create the module */
2547 PyObject *module = PyModule_Create(&interpretersmodule);
2548 if (module == NULL) {
2549 return NULL;
2550 }
2551
2552 /* Add exception types */
2553 PyObject *ns = PyModule_GetDict(module); // borrowed
2554 if (interp_exceptions_init(ns) != 0) {
2555 return NULL;
2556 }
2557 if (channel_exceptions_init(ns) != 0) {
2558 return NULL;
2559 }
2560
2561 /* Add other types */
2562 Py_INCREF(&ChannelIDtype);
2563 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2564 return NULL;
2565 }
Eric Snowbcfa4502019-03-01 16:50:31 -07002566 Py_INCREF(&_PyInterpreterID_Type);
2567 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&_PyInterpreterID_Type) != 0) {
Eric Snow4c6955e2018-02-16 18:53:40 -07002568 return NULL;
2569 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002570
Eric Snowbcfa4502019-03-01 16:50:31 -07002571 if (_PyCrossInterpreterData_RegisterClass(&ChannelIDtype, _channelid_shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002572 return NULL;
2573 }
2574
2575 return module;
2576}