blob: 72387d8da56b51b7d34128e1859efcfa2cb89317 [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"
7#include "internal/pystate.h"
8
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);
18 if (str == NULL) {
19 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{
29 PyThreadState *tstate = PyThreadState_Get();
30 // PyThreadState_Get() aborts if lookup fails, so we don't need
31 // to check the result for NULL.
32 return tstate->interp;
33}
34
35static int64_t
36_coerce_id(PyObject *id)
37{
38 id = PyNumber_Long(id);
39 if (id == NULL) {
40 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
41 PyErr_SetString(PyExc_TypeError,
42 "'id' must be a non-negative int");
43 }
44 else {
45 PyErr_SetString(PyExc_ValueError,
46 "'id' must be a non-negative int");
47 }
48 return -1;
49 }
Eric Snow4e9da0d2018-02-02 21:49:49 -070050 int64_t cid = PyLong_AsLongLong(id);
51 Py_DECREF(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -070052 if (cid == -1 && PyErr_Occurred() != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070053 if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
54 PyErr_SetString(PyExc_ValueError,
55 "'id' must be a non-negative int");
56 }
Eric Snow7f8bfc92018-01-29 18:23:44 -070057 return -1;
58 }
59 if (cid < 0) {
60 PyErr_SetString(PyExc_ValueError,
61 "'id' must be a non-negative int");
62 return -1;
63 }
Eric Snow7f8bfc92018-01-29 18:23:44 -070064 return cid;
65}
66
Eric Snow4e9da0d2018-02-02 21:49:49 -070067
Eric Snow7f8bfc92018-01-29 18:23:44 -070068/* data-sharing-specific code ***********************************************/
69
Eric Snow4e9da0d2018-02-02 21:49:49 -070070struct _sharednsitem {
71 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -070072 _PyCrossInterpreterData data;
Eric Snow4e9da0d2018-02-02 21:49:49 -070073};
Eric Snow7f8bfc92018-01-29 18:23:44 -070074
Eric Snow4e9da0d2018-02-02 21:49:49 -070075static int
76_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
Eric Snow7f8bfc92018-01-29 18:23:44 -070077{
Eric Snow4e9da0d2018-02-02 21:49:49 -070078 item->name = _copy_raw_string(key);
79 if (item->name == NULL) {
80 return -1;
Eric Snow7f8bfc92018-01-29 18:23:44 -070081 }
Eric Snow4e9da0d2018-02-02 21:49:49 -070082 if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
83 return -1;
84 }
85 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -070086}
87
Eric Snow4e9da0d2018-02-02 21:49:49 -070088static void
89_sharednsitem_clear(struct _sharednsitem *item)
90{
91 if (item->name != NULL) {
92 PyMem_Free(item->name);
93 }
94 _PyCrossInterpreterData_Release(&item->data);
95}
96
97static int
98_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
99{
100 PyObject *name = PyUnicode_FromString(item->name);
101 if (name == NULL) {
102 return -1;
103 }
104 PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
105 if (value == NULL) {
106 Py_DECREF(name);
107 return -1;
108 }
109 int res = PyDict_SetItem(ns, name, value);
110 Py_DECREF(name);
111 Py_DECREF(value);
112 return res;
113}
114
115typedef struct _sharedns {
116 Py_ssize_t len;
117 struct _sharednsitem* items;
118} _sharedns;
119
120static _sharedns *
121_sharedns_new(Py_ssize_t len)
122{
123 _sharedns *shared = PyMem_NEW(_sharedns, 1);
124 if (shared == NULL) {
125 PyErr_NoMemory();
126 return NULL;
127 }
128 shared->len = len;
129 shared->items = PyMem_NEW(struct _sharednsitem, len);
130 if (shared->items == NULL) {
131 PyErr_NoMemory();
132 PyMem_Free(shared);
133 return NULL;
134 }
135 return shared;
136}
137
138static void
139_sharedns_free(_sharedns *shared)
140{
141 for (Py_ssize_t i=0; i < shared->len; i++) {
142 _sharednsitem_clear(&shared->items[i]);
143 }
144 PyMem_Free(shared->items);
145 PyMem_Free(shared);
146}
147
148static _sharedns *
149_get_shared_ns(PyObject *shareable)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700150{
151 if (shareable == NULL || shareable == Py_None) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700152 return NULL;
153 }
154 Py_ssize_t len = PyDict_Size(shareable);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700155 if (len == 0) {
156 return NULL;
157 }
158
Eric Snow4e9da0d2018-02-02 21:49:49 -0700159 _sharedns *shared = _sharedns_new(len);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700160 if (shared == NULL) {
161 return NULL;
162 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700163 Py_ssize_t pos = 0;
164 for (Py_ssize_t i=0; i < len; i++) {
165 PyObject *key, *value;
166 if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
167 break;
168 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700169 if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700170 break;
171 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700172 }
173 if (PyErr_Occurred()) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700174 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700175 return NULL;
176 }
177 return shared;
178}
179
180static int
Eric Snow4e9da0d2018-02-02 21:49:49 -0700181_sharedns_apply(_sharedns *shared, PyObject *ns)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700182{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700183 for (Py_ssize_t i=0; i < shared->len; i++) {
184 if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
185 return -1;
186 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700187 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700188 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700189}
190
191// Ultimately we'd like to preserve enough information about the
192// exception and traceback that we could re-constitute (or at least
193// simulate, a la traceback.TracebackException), and even chain, a copy
194// of the exception in the calling interpreter.
195
196typedef struct _sharedexception {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700197 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700198 char *msg;
199} _sharedexception;
200
201static _sharedexception *
Eric Snow4e9da0d2018-02-02 21:49:49 -0700202_sharedexception_new(void)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700203{
204 _sharedexception *err = PyMem_NEW(_sharedexception, 1);
205 if (err == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700206 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700207 return NULL;
208 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700209 err->name = NULL;
210 err->msg = NULL;
211 return err;
212}
213
214static void
215_sharedexception_clear(_sharedexception *exc)
216{
217 if (exc->name != NULL) {
218 PyMem_Free(exc->name);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700219 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700220 if (exc->msg != NULL) {
221 PyMem_Free(exc->msg);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700222 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700223}
224
225static void
226_sharedexception_free(_sharedexception *exc)
227{
228 _sharedexception_clear(exc);
229 PyMem_Free(exc);
230}
231
232static _sharedexception *
233_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
234{
235 assert(exctype != NULL);
236 char *failure = NULL;
237
238 _sharedexception *err = _sharedexception_new();
239 if (err == NULL) {
240 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700241 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700242
243 PyObject *name = PyUnicode_FromFormat("%S", exctype);
244 if (name == NULL) {
245 failure = "unable to format exception type name";
246 goto finally;
247 }
248 err->name = _copy_raw_string(name);
249 Py_DECREF(name);
250 if (err->name == NULL) {
251 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
252 failure = "out of memory copying exception type name";
253 }
254 failure = "unable to encode and copy exception type name";
255 goto finally;
256 }
257
258 if (exc != NULL) {
259 PyObject *msg = PyUnicode_FromFormat("%S", exc);
260 if (msg == NULL) {
261 failure = "unable to format exception message";
262 goto finally;
263 }
264 err->msg = _copy_raw_string(msg);
265 Py_DECREF(msg);
266 if (err->msg == NULL) {
267 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
268 failure = "out of memory copying exception message";
269 }
270 failure = "unable to encode and copy exception message";
271 goto finally;
272 }
273 }
274
275finally:
276 if (failure != NULL) {
277 PyErr_Clear();
278 if (err->name != NULL) {
279 PyMem_Free(err->name);
280 err->name = NULL;
281 }
282 err->msg = failure;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700283 }
284 return err;
285}
286
Eric Snow7f8bfc92018-01-29 18:23:44 -0700287static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700288_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700289{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700290 if (exc->name != NULL) {
291 if (exc->msg != NULL) {
292 PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
293 }
294 else {
295 PyErr_SetString(wrapperclass, exc->name);
296 }
297 }
298 else if (exc->msg != NULL) {
299 PyErr_SetString(wrapperclass, exc->msg);
300 }
301 else {
302 PyErr_SetNone(wrapperclass);
303 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700304}
305
Eric Snow4e9da0d2018-02-02 21:49:49 -0700306
307/* channel-specific code ****************************************************/
Eric Snow7f8bfc92018-01-29 18:23:44 -0700308
Eric Snow3ab01362018-05-17 10:27:09 -0400309#define CHANNEL_SEND 1
310#define CHANNEL_BOTH 0
311#define CHANNEL_RECV -1
312
Eric Snow7f8bfc92018-01-29 18:23:44 -0700313static PyObject *ChannelError;
314static PyObject *ChannelNotFoundError;
315static PyObject *ChannelClosedError;
316static PyObject *ChannelEmptyError;
Eric Snow3ab01362018-05-17 10:27:09 -0400317static PyObject *ChannelNotEmptyError;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700318
319static int
320channel_exceptions_init(PyObject *ns)
321{
322 // XXX Move the exceptions into per-module memory?
323
324 // A channel-related operation failed.
325 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
326 PyExc_RuntimeError, NULL);
327 if (ChannelError == NULL) {
328 return -1;
329 }
330 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
331 return -1;
332 }
333
334 // An operation tried to use a channel that doesn't exist.
335 ChannelNotFoundError = PyErr_NewException(
336 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
337 if (ChannelNotFoundError == NULL) {
338 return -1;
339 }
340 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
341 return -1;
342 }
343
344 // An operation tried to use a closed channel.
345 ChannelClosedError = PyErr_NewException(
346 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
347 if (ChannelClosedError == NULL) {
348 return -1;
349 }
350 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
351 return -1;
352 }
353
354 // An operation tried to pop from an empty channel.
355 ChannelEmptyError = PyErr_NewException(
356 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
357 if (ChannelEmptyError == NULL) {
358 return -1;
359 }
360 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
361 return -1;
362 }
363
Eric Snow3ab01362018-05-17 10:27:09 -0400364 // An operation tried to close a non-empty channel.
365 ChannelNotEmptyError = PyErr_NewException(
366 "_xxsubinterpreters.ChannelNotEmptyError", ChannelError, NULL);
367 if (ChannelNotEmptyError == NULL) {
368 return -1;
369 }
370 if (PyDict_SetItemString(ns, "ChannelNotEmptyError", ChannelNotEmptyError) != 0) {
371 return -1;
372 }
373
Eric Snow7f8bfc92018-01-29 18:23:44 -0700374 return 0;
375}
376
Eric Snow4e9da0d2018-02-02 21:49:49 -0700377/* the channel queue */
378
379struct _channelitem;
380
381typedef struct _channelitem {
382 _PyCrossInterpreterData *data;
383 struct _channelitem *next;
384} _channelitem;
385
386static _channelitem *
387_channelitem_new(void)
388{
389 _channelitem *item = PyMem_NEW(_channelitem, 1);
390 if (item == NULL) {
391 PyErr_NoMemory();
392 return NULL;
393 }
394 item->data = NULL;
395 item->next = NULL;
396 return item;
397}
398
399static void
400_channelitem_clear(_channelitem *item)
401{
402 if (item->data != NULL) {
403 _PyCrossInterpreterData_Release(item->data);
404 PyMem_Free(item->data);
405 item->data = NULL;
406 }
407 item->next = NULL;
408}
409
410static void
411_channelitem_free(_channelitem *item)
412{
413 _channelitem_clear(item);
414 PyMem_Free(item);
415}
416
417static void
418_channelitem_free_all(_channelitem *item)
419{
420 while (item != NULL) {
421 _channelitem *last = item;
422 item = item->next;
423 _channelitem_free(last);
424 }
425}
426
427static _PyCrossInterpreterData *
428_channelitem_popped(_channelitem *item)
429{
430 _PyCrossInterpreterData *data = item->data;
431 item->data = NULL;
432 _channelitem_free(item);
433 return data;
434}
435
436typedef struct _channelqueue {
437 int64_t count;
438 _channelitem *first;
439 _channelitem *last;
440} _channelqueue;
441
442static _channelqueue *
443_channelqueue_new(void)
444{
445 _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
446 if (queue == NULL) {
447 PyErr_NoMemory();
448 return NULL;
449 }
450 queue->count = 0;
451 queue->first = NULL;
452 queue->last = NULL;
453 return queue;
454}
455
456static void
457_channelqueue_clear(_channelqueue *queue)
458{
459 _channelitem_free_all(queue->first);
460 queue->count = 0;
461 queue->first = NULL;
462 queue->last = NULL;
463}
464
465static void
466_channelqueue_free(_channelqueue *queue)
467{
468 _channelqueue_clear(queue);
469 PyMem_Free(queue);
470}
471
472static int
473_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
474{
475 _channelitem *item = _channelitem_new();
476 if (item == NULL) {
477 return -1;
478 }
479 item->data = data;
480
481 queue->count += 1;
482 if (queue->first == NULL) {
483 queue->first = item;
484 }
485 else {
486 queue->last->next = item;
487 }
488 queue->last = item;
489 return 0;
490}
491
492static _PyCrossInterpreterData *
493_channelqueue_get(_channelqueue *queue)
494{
495 _channelitem *item = queue->first;
496 if (item == NULL) {
497 return NULL;
498 }
499 queue->first = item->next;
500 if (queue->last == item) {
501 queue->last = NULL;
502 }
503 queue->count -= 1;
504
505 return _channelitem_popped(item);
506}
507
508/* channel-interpreter associations */
509
Eric Snow7f8bfc92018-01-29 18:23:44 -0700510struct _channelend;
511
512typedef struct _channelend {
513 struct _channelend *next;
514 int64_t interp;
515 int open;
516} _channelend;
517
518static _channelend *
519_channelend_new(int64_t interp)
520{
521 _channelend *end = PyMem_NEW(_channelend, 1);
522 if (end == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700523 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700524 return NULL;
525 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700526 end->next = NULL;
527 end->interp = interp;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700528 end->open = 1;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700529 return end;
530}
531
532static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700533_channelend_free(_channelend *end)
534{
535 PyMem_Free(end);
536}
537
538static void
539_channelend_free_all(_channelend *end)
540{
Eric Snow7f8bfc92018-01-29 18:23:44 -0700541 while (end != NULL) {
542 _channelend *last = end;
543 end = end->next;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700544 _channelend_free(last);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700545 }
546}
547
548static _channelend *
549_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
550{
551 _channelend *prev = NULL;
552 _channelend *end = first;
553 while (end != NULL) {
554 if (end->interp == interp) {
555 break;
556 }
557 prev = end;
558 end = end->next;
559 }
560 if (pprev != NULL) {
561 *pprev = prev;
562 }
563 return end;
564}
565
Eric Snow4e9da0d2018-02-02 21:49:49 -0700566typedef struct _channelassociations {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700567 // Note that the list entries are never removed for interpreter
568 // for which the channel is closed. This should be a problem in
569 // practice. Also, a channel isn't automatically closed when an
570 // interpreter is destroyed.
571 int64_t numsendopen;
572 int64_t numrecvopen;
573 _channelend *send;
574 _channelend *recv;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700575} _channelends;
576
577static _channelends *
578_channelends_new(void)
579{
580 _channelends *ends = PyMem_NEW(_channelends, 1);
581 if (ends== NULL) {
582 return NULL;
583 }
584 ends->numsendopen = 0;
585 ends->numrecvopen = 0;
586 ends->send = NULL;
587 ends->recv = NULL;
588 return ends;
589}
590
591static void
592_channelends_clear(_channelends *ends)
593{
594 _channelend_free_all(ends->send);
595 ends->send = NULL;
596 ends->numsendopen = 0;
597
598 _channelend_free_all(ends->recv);
599 ends->recv = NULL;
600 ends->numrecvopen = 0;
601}
602
603static void
604_channelends_free(_channelends *ends)
605{
606 _channelends_clear(ends);
607 PyMem_Free(ends);
608}
609
610static _channelend *
611_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
612 int send)
613{
614 _channelend *end = _channelend_new(interp);
615 if (end == NULL) {
616 return NULL;
617 }
618
619 if (prev == NULL) {
620 if (send) {
621 ends->send = end;
622 }
623 else {
624 ends->recv = end;
625 }
626 }
627 else {
628 prev->next = end;
629 }
630 if (send) {
631 ends->numsendopen += 1;
632 }
633 else {
634 ends->numrecvopen += 1;
635 }
636 return end;
637}
638
639static int
640_channelends_associate(_channelends *ends, int64_t interp, int send)
641{
642 _channelend *prev;
643 _channelend *end = _channelend_find(send ? ends->send : ends->recv,
644 interp, &prev);
645 if (end != NULL) {
646 if (!end->open) {
647 PyErr_SetString(ChannelClosedError, "channel already closed");
648 return -1;
649 }
650 // already associated
651 return 0;
652 }
653 if (_channelends_add(ends, prev, interp, send) == NULL) {
654 return -1;
655 }
656 return 0;
657}
658
659static int
660_channelends_is_open(_channelends *ends)
661{
662 if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
663 return 1;
664 }
665 if (ends->send == NULL && ends->recv == NULL) {
666 return 1;
667 }
668 return 0;
669}
670
671static void
672_channelends_close_end(_channelends *ends, _channelend *end, int send)
673{
674 end->open = 0;
675 if (send) {
676 ends->numsendopen -= 1;
677 }
678 else {
679 ends->numrecvopen -= 1;
680 }
681}
682
683static int
684_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
685{
686 _channelend *prev;
687 _channelend *end;
688 if (which >= 0) { // send/both
689 end = _channelend_find(ends->send, interp, &prev);
690 if (end == NULL) {
691 // never associated so add it
692 end = _channelends_add(ends, prev, interp, 1);
693 if (end == NULL) {
694 return -1;
695 }
696 }
697 _channelends_close_end(ends, end, 1);
698 }
699 if (which <= 0) { // recv/both
700 end = _channelend_find(ends->recv, interp, &prev);
701 if (end == NULL) {
702 // never associated so add it
703 end = _channelends_add(ends, prev, interp, 0);
704 if (end == NULL) {
705 return -1;
706 }
707 }
708 _channelends_close_end(ends, end, 0);
709 }
710 return 0;
711}
712
713static void
Eric Snow3ab01362018-05-17 10:27:09 -0400714_channelends_close_all(_channelends *ends, int which, int force)
Eric Snow4e9da0d2018-02-02 21:49:49 -0700715{
Eric Snow3ab01362018-05-17 10:27:09 -0400716 // XXX Handle the ends.
717 // XXX Handle force is True.
718
Eric Snow4e9da0d2018-02-02 21:49:49 -0700719 // Ensure all the "send"-associated interpreters are closed.
720 _channelend *end;
721 for (end = ends->send; end != NULL; end = end->next) {
722 _channelends_close_end(ends, end, 1);
723 }
724
725 // Ensure all the "recv"-associated interpreters are closed.
726 for (end = ends->recv; end != NULL; end = end->next) {
727 _channelends_close_end(ends, end, 0);
728 }
729}
730
731/* channels */
732
733struct _channel;
Eric Snow3ab01362018-05-17 10:27:09 -0400734struct _channel_closing;
735static void _channel_clear_closing(struct _channel *);
736static void _channel_finish_closing(struct _channel *);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700737
738typedef struct _channel {
739 PyThread_type_lock mutex;
740 _channelqueue *queue;
741 _channelends *ends;
742 int open;
Eric Snow3ab01362018-05-17 10:27:09 -0400743 struct _channel_closing *closing;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700744} _PyChannelState;
745
746static _PyChannelState *
747_channel_new(void)
748{
749 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
750 if (chan == NULL) {
751 return NULL;
752 }
753 chan->mutex = PyThread_allocate_lock();
754 if (chan->mutex == NULL) {
755 PyMem_Free(chan);
756 PyErr_SetString(ChannelError,
757 "can't initialize mutex for new channel");
758 return NULL;
759 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700760 chan->queue = _channelqueue_new();
761 if (chan->queue == NULL) {
762 PyMem_Free(chan);
763 return NULL;
764 }
765 chan->ends = _channelends_new();
766 if (chan->ends == NULL) {
767 _channelqueue_free(chan->queue);
768 PyMem_Free(chan);
769 return NULL;
770 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700771 chan->open = 1;
Eric Snow3ab01362018-05-17 10:27:09 -0400772 chan->closing = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700773 return chan;
774}
775
Eric Snow4e9da0d2018-02-02 21:49:49 -0700776static void
777_channel_free(_PyChannelState *chan)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700778{
Eric Snow3ab01362018-05-17 10:27:09 -0400779 _channel_clear_closing(chan);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700780 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
781 _channelqueue_free(chan->queue);
782 _channelends_free(chan->ends);
783 PyThread_release_lock(chan->mutex);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700784
Eric Snow4e9da0d2018-02-02 21:49:49 -0700785 PyThread_free_lock(chan->mutex);
786 PyMem_Free(chan);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700787}
788
Eric Snow4e9da0d2018-02-02 21:49:49 -0700789static int
790_channel_add(_PyChannelState *chan, int64_t interp,
791 _PyCrossInterpreterData *data)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700792{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700793 int res = -1;
794 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
795
Eric Snow7f8bfc92018-01-29 18:23:44 -0700796 if (!chan->open) {
797 PyErr_SetString(ChannelClosedError, "channel closed");
Eric Snow4e9da0d2018-02-02 21:49:49 -0700798 goto done;
799 }
800 if (_channelends_associate(chan->ends, interp, 1) != 0) {
801 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700802 }
803
Eric Snow4e9da0d2018-02-02 21:49:49 -0700804 if (_channelqueue_put(chan->queue, data) != 0) {
805 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700806 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700807
808 res = 0;
809done:
810 PyThread_release_lock(chan->mutex);
811 return res;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700812}
813
Eric Snow4e9da0d2018-02-02 21:49:49 -0700814static _PyCrossInterpreterData *
815_channel_next(_PyChannelState *chan, int64_t interp)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700816{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700817 _PyCrossInterpreterData *data = NULL;
818 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
819
820 if (!chan->open) {
821 PyErr_SetString(ChannelClosedError, "channel closed");
822 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700823 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700824 if (_channelends_associate(chan->ends, interp, 0) != 0) {
825 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700826 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700827
828 data = _channelqueue_get(chan->queue);
Eric Snow3ab01362018-05-17 10:27:09 -0400829 if (data == NULL && !PyErr_Occurred() && chan->closing != NULL) {
830 chan->open = 0;
831 }
832
Eric Snow4e9da0d2018-02-02 21:49:49 -0700833done:
834 PyThread_release_lock(chan->mutex);
Eric Snow3ab01362018-05-17 10:27:09 -0400835 if (chan->queue->count == 0) {
836 _channel_finish_closing(chan);
837 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700838 return data;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700839}
840
841static int
Eric Snow3ab01362018-05-17 10:27:09 -0400842_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700843{
844 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
845
846 int res = -1;
847 if (!chan->open) {
848 PyErr_SetString(ChannelClosedError, "channel already closed");
849 goto done;
850 }
851
Eric Snow3ab01362018-05-17 10:27:09 -0400852 if (_channelends_close_interpreter(chan->ends, interp, end) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700853 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700854 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700855 chan->open = _channelends_is_open(chan->ends);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700856
857 res = 0;
858done:
859 PyThread_release_lock(chan->mutex);
860 return res;
861}
862
863static int
Eric Snow3ab01362018-05-17 10:27:09 -0400864_channel_close_all(_PyChannelState *chan, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700865{
866 int res = -1;
867 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
868
869 if (!chan->open) {
870 PyErr_SetString(ChannelClosedError, "channel already closed");
871 goto done;
872 }
873
Eric Snow3ab01362018-05-17 10:27:09 -0400874 if (!force && chan->queue->count > 0) {
875 PyErr_SetString(ChannelNotEmptyError,
876 "may not be closed if not empty (try force=True)");
877 goto done;
878 }
879
Eric Snow7f8bfc92018-01-29 18:23:44 -0700880 chan->open = 0;
881
882 // We *could* also just leave these in place, since we've marked
883 // the channel as closed already.
Eric Snow3ab01362018-05-17 10:27:09 -0400884 _channelends_close_all(chan->ends, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700885
886 res = 0;
887done:
888 PyThread_release_lock(chan->mutex);
889 return res;
890}
891
Eric Snow4e9da0d2018-02-02 21:49:49 -0700892/* the set of channels */
Eric Snow7f8bfc92018-01-29 18:23:44 -0700893
894struct _channelref;
895
896typedef struct _channelref {
897 int64_t id;
898 _PyChannelState *chan;
899 struct _channelref *next;
900 Py_ssize_t objcount;
901} _channelref;
902
903static _channelref *
904_channelref_new(int64_t id, _PyChannelState *chan)
905{
906 _channelref *ref = PyMem_NEW(_channelref, 1);
907 if (ref == NULL) {
908 return NULL;
909 }
910 ref->id = id;
911 ref->chan = chan;
912 ref->next = NULL;
913 ref->objcount = 0;
914 return ref;
915}
916
Eric Snow4e9da0d2018-02-02 21:49:49 -0700917//static void
918//_channelref_clear(_channelref *ref)
919//{
920// ref->id = -1;
921// ref->chan = NULL;
922// ref->next = NULL;
923// ref->objcount = 0;
924//}
925
926static void
927_channelref_free(_channelref *ref)
928{
Eric Snow3ab01362018-05-17 10:27:09 -0400929 if (ref->chan != NULL) {
930 _channel_clear_closing(ref->chan);
931 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700932 //_channelref_clear(ref);
933 PyMem_Free(ref);
934}
935
Eric Snow7f8bfc92018-01-29 18:23:44 -0700936static _channelref *
937_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
938{
939 _channelref *prev = NULL;
940 _channelref *ref = first;
941 while (ref != NULL) {
942 if (ref->id == id) {
943 break;
944 }
945 prev = ref;
946 ref = ref->next;
947 }
948 if (pprev != NULL) {
949 *pprev = prev;
950 }
951 return ref;
952}
953
954typedef struct _channels {
955 PyThread_type_lock mutex;
956 _channelref *head;
957 int64_t numopen;
958 int64_t next_id;
959} _channels;
960
961static int
962_channels_init(_channels *channels)
963{
964 if (channels->mutex == NULL) {
965 channels->mutex = PyThread_allocate_lock();
966 if (channels->mutex == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700967 PyErr_SetString(ChannelError,
968 "can't initialize mutex for channel management");
969 return -1;
970 }
971 }
972 channels->head = NULL;
973 channels->numopen = 0;
974 channels->next_id = 0;
975 return 0;
976}
977
978static int64_t
979_channels_next_id(_channels *channels) // needs lock
980{
981 int64_t id = channels->next_id;
982 if (id < 0) {
983 /* overflow */
984 PyErr_SetString(ChannelError,
985 "failed to get a channel ID");
986 return -1;
987 }
988 channels->next_id += 1;
989 return id;
990}
991
992static _PyChannelState *
993_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
994{
995 _PyChannelState *chan = NULL;
996 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
997 if (pmutex != NULL) {
998 *pmutex = NULL;
999 }
1000
1001 _channelref *ref = _channelref_find(channels->head, id, NULL);
1002 if (ref == NULL) {
1003 PyErr_Format(ChannelNotFoundError, "channel %d not found", id);
1004 goto done;
1005 }
1006 if (ref->chan == NULL || !ref->chan->open) {
1007 PyErr_Format(ChannelClosedError, "channel %d closed", id);
1008 goto done;
1009 }
1010
1011 if (pmutex != NULL) {
1012 // The mutex will be closed by the caller.
1013 *pmutex = channels->mutex;
1014 }
1015
1016 chan = ref->chan;
1017done:
1018 if (pmutex == NULL || *pmutex == NULL) {
1019 PyThread_release_lock(channels->mutex);
1020 }
1021 return chan;
1022}
1023
1024static int64_t
1025_channels_add(_channels *channels, _PyChannelState *chan)
1026{
1027 int64_t cid = -1;
1028 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1029
1030 // Create a new ref.
1031 int64_t id = _channels_next_id(channels);
1032 if (id < 0) {
1033 goto done;
1034 }
1035 _channelref *ref = _channelref_new(id, chan);
1036 if (ref == NULL) {
1037 goto done;
1038 }
1039
1040 // Add it to the list.
1041 // We assume that the channel is a new one (not already in the list).
1042 ref->next = channels->head;
1043 channels->head = ref;
1044 channels->numopen += 1;
1045
1046 cid = id;
1047done:
1048 PyThread_release_lock(channels->mutex);
1049 return cid;
1050}
1051
Eric Snow3ab01362018-05-17 10:27:09 -04001052/* forward */
1053static int _channel_set_closing(struct _channelref *, PyThread_type_lock);
1054
Eric Snow7f8bfc92018-01-29 18:23:44 -07001055static int
Eric Snow3ab01362018-05-17 10:27:09 -04001056_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan,
1057 int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001058{
1059 int res = -1;
1060 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1061 if (pchan != NULL) {
1062 *pchan = NULL;
1063 }
1064
1065 _channelref *ref = _channelref_find(channels->head, cid, NULL);
1066 if (ref == NULL) {
1067 PyErr_Format(ChannelNotFoundError, "channel %d not found", cid);
1068 goto done;
1069 }
1070
1071 if (ref->chan == NULL) {
1072 PyErr_Format(ChannelClosedError, "channel %d closed", cid);
1073 goto done;
1074 }
Eric Snow3ab01362018-05-17 10:27:09 -04001075 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
1076 PyErr_Format(ChannelClosedError, "channel %d closed", cid);
1077 goto done;
1078 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001079 else {
Eric Snow3ab01362018-05-17 10:27:09 -04001080 if (_channel_close_all(ref->chan, end, force) != 0) {
1081 if (end == CHANNEL_SEND &&
1082 PyErr_ExceptionMatches(ChannelNotEmptyError)) {
1083 if (ref->chan->closing != NULL) {
1084 PyErr_Format(ChannelClosedError, "channel %d closed", cid);
1085 goto done;
1086 }
1087 // Mark the channel as closing and return. The channel
1088 // will be cleaned up in _channel_next().
1089 PyErr_Clear();
1090 if (_channel_set_closing(ref, channels->mutex) != 0) {
1091 goto done;
1092 }
1093 if (pchan != NULL) {
1094 *pchan = ref->chan;
1095 }
1096 res = 0;
1097 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001098 goto done;
1099 }
1100 if (pchan != NULL) {
1101 *pchan = ref->chan;
1102 }
Eric Snow3ab01362018-05-17 10:27:09 -04001103 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001104 _channel_free(ref->chan);
1105 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001106 ref->chan = NULL;
1107 }
1108
1109 res = 0;
1110done:
1111 PyThread_release_lock(channels->mutex);
1112 return res;
1113}
1114
1115static void
1116_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1117 _PyChannelState **pchan)
1118{
1119 if (ref == channels->head) {
1120 channels->head = ref->next;
1121 }
1122 else {
1123 prev->next = ref->next;
1124 }
1125 channels->numopen -= 1;
1126
1127 if (pchan != NULL) {
1128 *pchan = ref->chan;
1129 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001130 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001131}
1132
1133static int
1134_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1135{
1136 int res = -1;
1137 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1138
1139 if (pchan != NULL) {
1140 *pchan = NULL;
1141 }
1142
1143 _channelref *prev = NULL;
1144 _channelref *ref = _channelref_find(channels->head, id, &prev);
1145 if (ref == NULL) {
1146 PyErr_Format(ChannelNotFoundError, "channel %d not found", id);
1147 goto done;
1148 }
1149
1150 _channels_remove_ref(channels, ref, prev, pchan);
1151
1152 res = 0;
1153done:
1154 PyThread_release_lock(channels->mutex);
1155 return res;
1156}
1157
1158static int
1159_channels_add_id_object(_channels *channels, int64_t id)
1160{
1161 int res = -1;
1162 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1163
1164 _channelref *ref = _channelref_find(channels->head, id, NULL);
1165 if (ref == NULL) {
1166 PyErr_Format(ChannelNotFoundError, "channel %d not found", id);
1167 goto done;
1168 }
1169 ref->objcount += 1;
1170
1171 res = 0;
1172done:
1173 PyThread_release_lock(channels->mutex);
1174 return res;
1175}
1176
1177static void
1178_channels_drop_id_object(_channels *channels, int64_t id)
1179{
1180 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1181
1182 _channelref *prev = NULL;
1183 _channelref *ref = _channelref_find(channels->head, id, &prev);
1184 if (ref == NULL) {
1185 // Already destroyed.
1186 goto done;
1187 }
1188 ref->objcount -= 1;
1189
1190 // Destroy if no longer used.
1191 if (ref->objcount == 0) {
1192 _PyChannelState *chan = NULL;
1193 _channels_remove_ref(channels, ref, prev, &chan);
1194 if (chan != NULL) {
1195 _channel_free(chan);
1196 }
1197 }
1198
1199done:
1200 PyThread_release_lock(channels->mutex);
1201}
1202
1203int64_t *
1204_channels_list_all(_channels *channels, int64_t *count)
1205{
1206 int64_t *cids = NULL;
1207 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1208 int64_t numopen = channels->numopen;
1209 if (numopen >= PY_SSIZE_T_MAX) {
1210 PyErr_SetString(PyExc_RuntimeError, "too many channels open");
1211 goto done;
1212 }
1213 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
1214 if (ids == NULL) {
1215 goto done;
1216 }
1217 _channelref *ref = channels->head;
1218 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
1219 ids[i] = ref->id;
1220 }
1221 *count = channels->numopen;
1222
1223 cids = ids;
1224done:
1225 PyThread_release_lock(channels->mutex);
1226 return cids;
1227}
1228
Eric Snow3ab01362018-05-17 10:27:09 -04001229/* support for closing non-empty channels */
1230
1231struct _channel_closing {
1232 struct _channelref *ref;
1233};
1234
1235static int
1236_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
1237 struct _channel *chan = ref->chan;
1238 if (chan == NULL) {
1239 // already closed
1240 return 0;
1241 }
1242 int res = -1;
1243 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1244 if (chan->closing != NULL) {
1245 PyErr_SetString(ChannelClosedError, "channel closed");
1246 goto done;
1247 }
1248 chan->closing = PyMem_NEW(struct _channel_closing, 1);
1249 if (chan->closing == NULL) {
1250 goto done;
1251 }
1252 chan->closing->ref = ref;
1253
1254 res = 0;
1255done:
1256 PyThread_release_lock(chan->mutex);
1257 return res;
1258}
1259
1260static void
1261_channel_clear_closing(struct _channel *chan) {
1262 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1263 if (chan->closing != NULL) {
1264 PyMem_Free(chan->closing);
1265 chan->closing = NULL;
1266 }
1267 PyThread_release_lock(chan->mutex);
1268}
1269
1270static void
1271_channel_finish_closing(struct _channel *chan) {
1272 struct _channel_closing *closing = chan->closing;
1273 if (closing == NULL) {
1274 return;
1275 }
1276 _channelref *ref = closing->ref;
1277 _channel_clear_closing(chan);
1278 // Do the things that would have been done in _channels_close().
1279 ref->chan = NULL;
1280 _channel_free(chan);
1281};
1282
Eric Snow7f8bfc92018-01-29 18:23:44 -07001283/* "high"-level channel-related functions */
1284
1285static int64_t
1286_channel_create(_channels *channels)
1287{
1288 _PyChannelState *chan = _channel_new();
1289 if (chan == NULL) {
1290 return -1;
1291 }
1292 int64_t id = _channels_add(channels, chan);
1293 if (id < 0) {
1294 _channel_free(chan);
1295 return -1;
1296 }
1297 return id;
1298}
1299
1300static int
1301_channel_destroy(_channels *channels, int64_t id)
1302{
1303 _PyChannelState *chan = NULL;
1304 if (_channels_remove(channels, id, &chan) != 0) {
1305 return -1;
1306 }
1307 if (chan != NULL) {
1308 _channel_free(chan);
1309 }
1310 return 0;
1311}
1312
1313static int
1314_channel_send(_channels *channels, int64_t id, PyObject *obj)
1315{
1316 PyInterpreterState *interp = _get_current();
1317 if (interp == NULL) {
1318 return -1;
1319 }
1320
1321 // Look up the channel.
1322 PyThread_type_lock mutex = NULL;
1323 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1324 if (chan == NULL) {
1325 return -1;
1326 }
1327 // Past this point we are responsible for releasing the mutex.
1328
Eric Snow3ab01362018-05-17 10:27:09 -04001329 if (chan->closing != NULL) {
1330 PyErr_Format(ChannelClosedError, "channel %d closed", id);
1331 PyThread_release_lock(mutex);
1332 return -1;
1333 }
1334
Eric Snow7f8bfc92018-01-29 18:23:44 -07001335 // Convert the object to cross-interpreter data.
1336 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
1337 if (data == NULL) {
1338 PyThread_release_lock(mutex);
1339 return -1;
1340 }
1341 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
1342 PyThread_release_lock(mutex);
1343 return -1;
1344 }
1345
1346 // Add the data to the channel.
1347 int res = _channel_add(chan, interp->id, data);
1348 PyThread_release_lock(mutex);
1349 if (res != 0) {
1350 _PyCrossInterpreterData_Release(data);
1351 PyMem_Free(data);
1352 return -1;
1353 }
1354
1355 return 0;
1356}
1357
1358static PyObject *
1359_channel_recv(_channels *channels, int64_t id)
1360{
1361 PyInterpreterState *interp = _get_current();
1362 if (interp == NULL) {
1363 return NULL;
1364 }
1365
1366 // Look up the channel.
1367 PyThread_type_lock mutex = NULL;
1368 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1369 if (chan == NULL) {
1370 return NULL;
1371 }
1372 // Past this point we are responsible for releasing the mutex.
1373
1374 // Pop off the next item from the channel.
1375 _PyCrossInterpreterData *data = _channel_next(chan, interp->id);
1376 PyThread_release_lock(mutex);
1377 if (data == NULL) {
Eric Snow6d2cd902018-05-16 15:04:57 -04001378 if (!PyErr_Occurred()) {
1379 PyErr_Format(ChannelEmptyError, "channel %d is empty", id);
1380 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001381 return NULL;
1382 }
1383
1384 // Convert the data back to an object.
1385 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
1386 if (obj == NULL) {
1387 return NULL;
1388 }
1389 _PyCrossInterpreterData_Release(data);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001390 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001391
1392 return obj;
1393}
1394
1395static int
1396_channel_drop(_channels *channels, int64_t id, int send, int recv)
1397{
1398 PyInterpreterState *interp = _get_current();
1399 if (interp == NULL) {
1400 return -1;
1401 }
1402
1403 // Look up the channel.
1404 PyThread_type_lock mutex = NULL;
1405 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1406 if (chan == NULL) {
1407 return -1;
1408 }
1409 // Past this point we are responsible for releasing the mutex.
1410
1411 // Close one or both of the two ends.
Eric Snow4e9da0d2018-02-02 21:49:49 -07001412 int res = _channel_close_interpreter(chan, interp->id, send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001413 PyThread_release_lock(mutex);
1414 return res;
1415}
1416
1417static int
Eric Snow3ab01362018-05-17 10:27:09 -04001418_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001419{
Eric Snow3ab01362018-05-17 10:27:09 -04001420 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001421}
1422
1423/* ChannelID class */
1424
Eric Snow7f8bfc92018-01-29 18:23:44 -07001425static PyTypeObject ChannelIDtype;
1426
1427typedef struct channelid {
1428 PyObject_HEAD
1429 int64_t id;
1430 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001431 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001432 _channels *channels;
1433} channelid;
1434
1435static channelid *
1436newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001437 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001438{
1439 channelid *self = PyObject_New(channelid, cls);
1440 if (self == NULL) {
1441 return NULL;
1442 }
1443 self->id = cid;
1444 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001445 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001446 self->channels = channels;
1447
1448 if (_channels_add_id_object(channels, cid) != 0) {
1449 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1450 PyErr_Clear();
1451 }
1452 else {
1453 Py_DECREF((PyObject *)self);
1454 return NULL;
1455 }
1456 }
1457
1458 return self;
1459}
1460
1461static _channels * _global_channels(void);
1462
1463static PyObject *
1464channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1465{
Eric Snow6d2cd902018-05-16 15:04:57 -04001466 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07001467 PyObject *id;
1468 int send = -1;
1469 int recv = -1;
1470 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001471 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001472 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04001473 "O|$pppp:ChannelID.__new__", kwlist,
1474 &id, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001475 return NULL;
1476
1477 // Coerce and check the ID.
1478 int64_t cid;
1479 if (PyObject_TypeCheck(id, &ChannelIDtype)) {
1480 cid = ((channelid *)id)->id;
1481 }
1482 else {
1483 cid = _coerce_id(id);
1484 if (cid < 0) {
1485 return NULL;
1486 }
1487 }
1488
1489 // Handle "send" and "recv".
1490 if (send == 0 && recv == 0) {
1491 PyErr_SetString(PyExc_ValueError,
1492 "'send' and 'recv' cannot both be False");
1493 return NULL;
1494 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001495
Eric Snow7f8bfc92018-01-29 18:23:44 -07001496 int end = 0;
1497 if (send == 1) {
1498 if (recv == 0 || recv == -1) {
1499 end = CHANNEL_SEND;
1500 }
1501 }
1502 else if (recv == 1) {
1503 end = CHANNEL_RECV;
1504 }
1505
Eric Snow6d2cd902018-05-16 15:04:57 -04001506 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
1507 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001508}
1509
1510static void
1511channelid_dealloc(PyObject *v)
1512{
1513 int64_t cid = ((channelid *)v)->id;
1514 _channels *channels = ((channelid *)v)->channels;
1515 Py_TYPE(v)->tp_free(v);
1516
1517 _channels_drop_id_object(channels, cid);
1518}
1519
1520static PyObject *
1521channelid_repr(PyObject *self)
1522{
1523 PyTypeObject *type = Py_TYPE(self);
1524 const char *name = _PyType_Name(type);
1525
1526 channelid *cid = (channelid *)self;
1527 const char *fmt;
1528 if (cid->end == CHANNEL_SEND) {
1529 fmt = "%s(%d, send=True)";
1530 }
1531 else if (cid->end == CHANNEL_RECV) {
1532 fmt = "%s(%d, recv=True)";
1533 }
1534 else {
1535 fmt = "%s(%d)";
1536 }
1537 return PyUnicode_FromFormat(fmt, name, cid->id);
1538}
1539
Eric Snow6d2cd902018-05-16 15:04:57 -04001540static PyObject *
1541channelid_str(PyObject *self)
1542{
1543 channelid *cid = (channelid *)self;
1544 return PyUnicode_FromFormat("%d", cid->id);
1545}
1546
Eric Snow7f8bfc92018-01-29 18:23:44 -07001547PyObject *
1548channelid_int(PyObject *self)
1549{
1550 channelid *cid = (channelid *)self;
1551 return PyLong_FromLongLong(cid->id);
1552}
1553
1554static PyNumberMethods channelid_as_number = {
1555 0, /* nb_add */
1556 0, /* nb_subtract */
1557 0, /* nb_multiply */
1558 0, /* nb_remainder */
1559 0, /* nb_divmod */
1560 0, /* nb_power */
1561 0, /* nb_negative */
1562 0, /* nb_positive */
1563 0, /* nb_absolute */
1564 0, /* nb_bool */
1565 0, /* nb_invert */
1566 0, /* nb_lshift */
1567 0, /* nb_rshift */
1568 0, /* nb_and */
1569 0, /* nb_xor */
1570 0, /* nb_or */
1571 (unaryfunc)channelid_int, /* nb_int */
1572 0, /* nb_reserved */
1573 0, /* nb_float */
1574
1575 0, /* nb_inplace_add */
1576 0, /* nb_inplace_subtract */
1577 0, /* nb_inplace_multiply */
1578 0, /* nb_inplace_remainder */
1579 0, /* nb_inplace_power */
1580 0, /* nb_inplace_lshift */
1581 0, /* nb_inplace_rshift */
1582 0, /* nb_inplace_and */
1583 0, /* nb_inplace_xor */
1584 0, /* nb_inplace_or */
1585
1586 0, /* nb_floor_divide */
1587 0, /* nb_true_divide */
1588 0, /* nb_inplace_floor_divide */
1589 0, /* nb_inplace_true_divide */
1590
1591 (unaryfunc)channelid_int, /* nb_index */
1592};
1593
1594static Py_hash_t
1595channelid_hash(PyObject *self)
1596{
1597 channelid *cid = (channelid *)self;
1598 PyObject *id = PyLong_FromLongLong(cid->id);
1599 if (id == NULL) {
1600 return -1;
1601 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001602 Py_hash_t hash = PyObject_Hash(id);
1603 Py_DECREF(id);
1604 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001605}
1606
1607static PyObject *
1608channelid_richcompare(PyObject *self, PyObject *other, int op)
1609{
1610 if (op != Py_EQ && op != Py_NE) {
1611 Py_RETURN_NOTIMPLEMENTED;
1612 }
1613
1614 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1615 Py_RETURN_NOTIMPLEMENTED;
1616 }
1617
1618 channelid *cid = (channelid *)self;
1619 int equal;
1620 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1621 channelid *othercid = (channelid *)other;
1622 if (cid->end != othercid->end) {
1623 equal = 0;
1624 }
1625 else {
1626 equal = (cid->id == othercid->id);
1627 }
1628 }
1629 else {
1630 other = PyNumber_Long(other);
1631 if (other == NULL) {
1632 PyErr_Clear();
1633 Py_RETURN_NOTIMPLEMENTED;
1634 }
1635 int64_t othercid = PyLong_AsLongLong(other);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001636 Py_DECREF(other);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001637 if (othercid == -1 && PyErr_Occurred() != NULL) {
1638 return NULL;
1639 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001640 if (othercid < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001641 equal = 0;
1642 }
1643 else {
1644 equal = (cid->id == othercid);
1645 }
1646 }
1647
1648 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1649 Py_RETURN_TRUE;
1650 }
1651 Py_RETURN_FALSE;
1652}
1653
1654struct _channelid_xid {
1655 int64_t id;
1656 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001657 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001658};
1659
1660static PyObject *
1661_channelid_from_xid(_PyCrossInterpreterData *data)
1662{
1663 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001664 // Note that we do not preserve the "resolve" flag.
1665 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1666 _global_channels(), 0, 0);
1667 if (xid->end == 0) {
1668 return cid;
1669 }
1670 if (!xid->resolve) {
1671 return cid;
1672 }
1673
1674 /* Try returning a high-level channel end but fall back to the ID. */
1675 PyObject *highlevel = PyImport_ImportModule("interpreters");
1676 if (highlevel == NULL) {
1677 PyErr_Clear();
1678 highlevel = PyImport_ImportModule("test.support.interpreters");
1679 if (highlevel == NULL) {
1680 goto error;
1681 }
1682 }
1683 const char *clsname = (xid->end == CHANNEL_RECV) ? "RecvChannel" :
1684 "SendChannel";
1685 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1686 Py_DECREF(highlevel);
1687 if (cls == NULL) {
1688 goto error;
1689 }
1690 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1691 if (chan == NULL) {
1692 goto error;
1693 }
1694 Py_DECREF(cid);
1695 return chan;
1696
1697error:
1698 PyErr_Clear();
1699 return cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001700}
1701
1702static int
1703_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1704{
1705 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1706 if (xid == NULL) {
1707 return -1;
1708 }
1709 xid->id = ((channelid *)obj)->id;
1710 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001711 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001712
1713 data->data = xid;
1714 data->obj = obj;
1715 data->new_object = _channelid_from_xid;
1716 data->free = PyMem_Free;
1717 return 0;
1718}
1719
1720static PyObject *
1721channelid_end(PyObject *self, void *end)
1722{
1723 int force = 1;
1724 channelid *cid = (channelid *)self;
1725 if (end != NULL) {
1726 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001727 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001728 }
1729
1730 if (cid->end == CHANNEL_SEND) {
1731 return PyUnicode_InternFromString("send");
1732 }
1733 if (cid->end == CHANNEL_RECV) {
1734 return PyUnicode_InternFromString("recv");
1735 }
1736 return PyUnicode_InternFromString("both");
1737}
1738
1739static int _channelid_end_send = CHANNEL_SEND;
1740static int _channelid_end_recv = CHANNEL_RECV;
1741
1742static PyGetSetDef channelid_getsets[] = {
1743 {"end", (getter)channelid_end, NULL,
1744 PyDoc_STR("'send', 'recv', or 'both'")},
1745 {"send", (getter)channelid_end, NULL,
1746 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1747 {"recv", (getter)channelid_end, NULL,
1748 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1749 {NULL}
1750};
1751
1752PyDoc_STRVAR(channelid_doc,
1753"A channel ID identifies a channel and may be used as an int.");
1754
1755static PyTypeObject ChannelIDtype = {
1756 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1757 "_xxsubinterpreters.ChannelID", /* tp_name */
1758 sizeof(channelid), /* tp_size */
1759 0, /* tp_itemsize */
1760 (destructor)channelid_dealloc, /* tp_dealloc */
1761 0, /* tp_print */
1762 0, /* tp_getattr */
1763 0, /* tp_setattr */
1764 0, /* tp_as_async */
1765 (reprfunc)channelid_repr, /* tp_repr */
1766 &channelid_as_number, /* tp_as_number */
1767 0, /* tp_as_sequence */
1768 0, /* tp_as_mapping */
1769 channelid_hash, /* tp_hash */
1770 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001771 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001772 0, /* tp_getattro */
1773 0, /* tp_setattro */
1774 0, /* tp_as_buffer */
1775 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1776 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
1777 channelid_doc, /* tp_doc */
1778 0, /* tp_traverse */
1779 0, /* tp_clear */
1780 channelid_richcompare, /* tp_richcompare */
1781 0, /* tp_weaklistoffset */
1782 0, /* tp_iter */
1783 0, /* tp_iternext */
1784 0, /* tp_methods */
1785 0, /* tp_members */
1786 channelid_getsets, /* tp_getset */
1787 0, /* tp_base */
1788 0, /* tp_dict */
1789 0, /* tp_descr_get */
1790 0, /* tp_descr_set */
1791 0, /* tp_dictoffset */
1792 0, /* tp_init */
1793 0, /* tp_alloc */
1794 // Note that we do not set tp_new to channelid_new. Instead we
1795 // set it to NULL, meaning it cannot be instantiated from Python
1796 // code. We do this because there is a strong relationship between
1797 // channel IDs and the channel lifecycle, so this limitation avoids
1798 // related complications.
1799 NULL, /* tp_new */
1800};
1801
Eric Snow4e9da0d2018-02-02 21:49:49 -07001802
1803/* interpreter-specific code ************************************************/
1804
1805static PyObject * RunFailedError = NULL;
1806
1807static int
1808interp_exceptions_init(PyObject *ns)
1809{
1810 // XXX Move the exceptions into per-module memory?
1811
1812 if (RunFailedError == NULL) {
1813 // An uncaught exception came out of interp_run_string().
1814 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1815 PyExc_RuntimeError, NULL);
1816 if (RunFailedError == NULL) {
1817 return -1;
1818 }
1819 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1820 return -1;
1821 }
1822 }
1823
1824 return 0;
1825}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001826
Eric Snow7f8bfc92018-01-29 18:23:44 -07001827static int
1828_is_running(PyInterpreterState *interp)
1829{
1830 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1831 if (PyThreadState_Next(tstate) != NULL) {
1832 PyErr_SetString(PyExc_RuntimeError,
1833 "interpreter has more than one thread");
1834 return -1;
1835 }
1836 PyFrameObject *frame = tstate->frame;
1837 if (frame == NULL) {
1838 if (PyErr_Occurred() != NULL) {
1839 return -1;
1840 }
1841 return 0;
1842 }
1843 return (int)(frame->f_executing);
1844}
1845
1846static int
1847_ensure_not_running(PyInterpreterState *interp)
1848{
1849 int is_running = _is_running(interp);
1850 if (is_running < 0) {
1851 return -1;
1852 }
1853 if (is_running) {
1854 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1855 return -1;
1856 }
1857 return 0;
1858}
1859
1860static int
1861_run_script(PyInterpreterState *interp, const char *codestr,
Eric Snow4e9da0d2018-02-02 21:49:49 -07001862 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001863{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001864 PyObject *exctype = NULL;
1865 PyObject *excval = NULL;
1866 PyObject *tb = NULL;
1867
Eric Snow7f8bfc92018-01-29 18:23:44 -07001868 PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
1869 if (main_mod == NULL) {
1870 goto error;
1871 }
1872 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1873 Py_DECREF(main_mod);
1874 if (ns == NULL) {
1875 goto error;
1876 }
1877 Py_INCREF(ns);
1878
1879 // Apply the cross-interpreter data.
1880 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001881 if (_sharedns_apply(shared, ns) != 0) {
1882 Py_DECREF(ns);
1883 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001884 }
1885 }
1886
1887 // Run the string (see PyRun_SimpleStringFlags).
1888 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1889 Py_DECREF(ns);
1890 if (result == NULL) {
1891 goto error;
1892 }
1893 else {
1894 Py_DECREF(result); // We throw away the result.
1895 }
1896
Eric Snow4e9da0d2018-02-02 21:49:49 -07001897 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001898 return 0;
1899
1900error:
Eric Snow4e9da0d2018-02-02 21:49:49 -07001901 PyErr_Fetch(&exctype, &excval, &tb);
1902
1903 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1904 Py_XDECREF(exctype);
1905 Py_XDECREF(excval);
1906 Py_XDECREF(tb);
1907 if (sharedexc == NULL) {
1908 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1909 PyErr_Clear();
1910 sharedexc = NULL;
1911 }
1912 else {
1913 assert(!PyErr_Occurred());
1914 }
1915 *exc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001916 return -1;
1917}
1918
1919static int
1920_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1921 PyObject *shareables)
1922{
1923 if (_ensure_not_running(interp) < 0) {
1924 return -1;
1925 }
1926
Eric Snow4e9da0d2018-02-02 21:49:49 -07001927 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001928 if (shared == NULL && PyErr_Occurred()) {
1929 return -1;
1930 }
1931
1932 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001933 PyThreadState *save_tstate = NULL;
1934 if (interp != PyThreadState_Get()->interp) {
1935 // XXX Using the "head" thread isn't strictly correct.
1936 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1937 // XXX Possible GILState issues?
1938 save_tstate = PyThreadState_Swap(tstate);
1939 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001940
1941 // Run the script.
1942 _sharedexception *exc = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001943 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001944
1945 // Switch back.
1946 if (save_tstate != NULL) {
1947 PyThreadState_Swap(save_tstate);
1948 }
1949
1950 // Propagate any exception out to the caller.
1951 if (exc != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001952 _sharedexception_apply(exc, RunFailedError);
1953 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001954 }
1955 else if (result != 0) {
1956 // We were unable to allocate a shared exception.
1957 PyErr_NoMemory();
1958 }
1959
1960 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001961 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001962 }
1963
1964 return result;
1965}
1966
Eric Snow4c6955e2018-02-16 18:53:40 -07001967/* InterpreterID class */
1968
1969static PyTypeObject InterpreterIDtype;
1970
1971typedef struct interpid {
1972 PyObject_HEAD
1973 int64_t id;
1974} interpid;
1975
1976static interpid *
1977newinterpid(PyTypeObject *cls, int64_t id, int force)
1978{
1979 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
1980 if (interp == NULL) {
1981 if (force) {
1982 PyErr_Clear();
1983 }
1984 else {
1985 return NULL;
1986 }
1987 }
1988
1989 interpid *self = PyObject_New(interpid, cls);
1990 if (self == NULL) {
1991 return NULL;
1992 }
1993 self->id = id;
1994
1995 if (interp != NULL) {
1996 _PyInterpreterState_IDIncref(interp);
1997 }
1998 return self;
1999}
2000
2001static PyObject *
2002interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
2003{
2004 static char *kwlist[] = {"id", "force", NULL};
2005 PyObject *idobj;
2006 int force = 0;
2007 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2008 "O|$p:InterpreterID.__init__", kwlist,
2009 &idobj, &force)) {
2010 return NULL;
2011 }
2012
2013 // Coerce and check the ID.
2014 int64_t id;
2015 if (PyObject_TypeCheck(idobj, &InterpreterIDtype)) {
2016 id = ((interpid *)idobj)->id;
2017 }
2018 else {
2019 id = _coerce_id(idobj);
2020 if (id < 0) {
2021 return NULL;
2022 }
2023 }
2024
2025 return (PyObject *)newinterpid(cls, id, force);
2026}
2027
2028static void
2029interpid_dealloc(PyObject *v)
2030{
2031 int64_t id = ((interpid *)v)->id;
2032 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
2033 if (interp != NULL) {
2034 _PyInterpreterState_IDDecref(interp);
2035 }
2036 else {
2037 // already deleted
2038 PyErr_Clear();
2039 }
2040 Py_TYPE(v)->tp_free(v);
2041}
2042
2043static PyObject *
2044interpid_repr(PyObject *self)
2045{
2046 PyTypeObject *type = Py_TYPE(self);
2047 const char *name = _PyType_Name(type);
2048 interpid *id = (interpid *)self;
2049 return PyUnicode_FromFormat("%s(%d)", name, id->id);
2050}
2051
Eric Snow6d2cd902018-05-16 15:04:57 -04002052static PyObject *
2053interpid_str(PyObject *self)
2054{
2055 interpid *id = (interpid *)self;
2056 return PyUnicode_FromFormat("%d", id->id);
2057}
2058
Eric Snow4c6955e2018-02-16 18:53:40 -07002059PyObject *
2060interpid_int(PyObject *self)
2061{
2062 interpid *id = (interpid *)self;
2063 return PyLong_FromLongLong(id->id);
2064}
2065
2066static PyNumberMethods interpid_as_number = {
2067 0, /* nb_add */
2068 0, /* nb_subtract */
2069 0, /* nb_multiply */
2070 0, /* nb_remainder */
2071 0, /* nb_divmod */
2072 0, /* nb_power */
2073 0, /* nb_negative */
2074 0, /* nb_positive */
2075 0, /* nb_absolute */
2076 0, /* nb_bool */
2077 0, /* nb_invert */
2078 0, /* nb_lshift */
2079 0, /* nb_rshift */
2080 0, /* nb_and */
2081 0, /* nb_xor */
2082 0, /* nb_or */
2083 (unaryfunc)interpid_int, /* nb_int */
2084 0, /* nb_reserved */
2085 0, /* nb_float */
2086
2087 0, /* nb_inplace_add */
2088 0, /* nb_inplace_subtract */
2089 0, /* nb_inplace_multiply */
2090 0, /* nb_inplace_remainder */
2091 0, /* nb_inplace_power */
2092 0, /* nb_inplace_lshift */
2093 0, /* nb_inplace_rshift */
2094 0, /* nb_inplace_and */
2095 0, /* nb_inplace_xor */
2096 0, /* nb_inplace_or */
2097
2098 0, /* nb_floor_divide */
2099 0, /* nb_true_divide */
2100 0, /* nb_inplace_floor_divide */
2101 0, /* nb_inplace_true_divide */
2102
2103 (unaryfunc)interpid_int, /* nb_index */
2104};
2105
2106static Py_hash_t
2107interpid_hash(PyObject *self)
2108{
2109 interpid *id = (interpid *)self;
2110 PyObject *obj = PyLong_FromLongLong(id->id);
2111 if (obj == NULL) {
2112 return -1;
2113 }
2114 Py_hash_t hash = PyObject_Hash(obj);
2115 Py_DECREF(obj);
2116 return hash;
2117}
2118
2119static PyObject *
2120interpid_richcompare(PyObject *self, PyObject *other, int op)
2121{
2122 if (op != Py_EQ && op != Py_NE) {
2123 Py_RETURN_NOTIMPLEMENTED;
2124 }
2125
2126 if (!PyObject_TypeCheck(self, &InterpreterIDtype)) {
2127 Py_RETURN_NOTIMPLEMENTED;
2128 }
2129
2130 interpid *id = (interpid *)self;
2131 int equal;
2132 if (PyObject_TypeCheck(other, &InterpreterIDtype)) {
2133 interpid *otherid = (interpid *)other;
2134 equal = (id->id == otherid->id);
2135 }
2136 else {
2137 other = PyNumber_Long(other);
2138 if (other == NULL) {
2139 PyErr_Clear();
2140 Py_RETURN_NOTIMPLEMENTED;
2141 }
2142 int64_t otherid = PyLong_AsLongLong(other);
2143 Py_DECREF(other);
2144 if (otherid == -1 && PyErr_Occurred() != NULL) {
2145 return NULL;
2146 }
2147 if (otherid < 0) {
2148 equal = 0;
2149 }
2150 else {
2151 equal = (id->id == otherid);
2152 }
2153 }
2154
2155 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
2156 Py_RETURN_TRUE;
2157 }
2158 Py_RETURN_FALSE;
2159}
2160
2161PyDoc_STRVAR(interpid_doc,
2162"A interpreter ID identifies a interpreter and may be used as an int.");
2163
2164static PyTypeObject InterpreterIDtype = {
2165 PyVarObject_HEAD_INIT(&PyType_Type, 0)
2166 "interpreters.InterpreterID", /* tp_name */
2167 sizeof(interpid), /* tp_size */
2168 0, /* tp_itemsize */
2169 (destructor)interpid_dealloc, /* tp_dealloc */
2170 0, /* tp_print */
2171 0, /* tp_getattr */
2172 0, /* tp_setattr */
2173 0, /* tp_as_async */
2174 (reprfunc)interpid_repr, /* tp_repr */
2175 &interpid_as_number, /* tp_as_number */
2176 0, /* tp_as_sequence */
2177 0, /* tp_as_mapping */
2178 interpid_hash, /* tp_hash */
2179 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04002180 (reprfunc)interpid_str, /* tp_str */
Eric Snow4c6955e2018-02-16 18:53:40 -07002181 0, /* tp_getattro */
2182 0, /* tp_setattro */
2183 0, /* tp_as_buffer */
2184 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
2185 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
2186 interpid_doc, /* tp_doc */
2187 0, /* tp_traverse */
2188 0, /* tp_clear */
2189 interpid_richcompare, /* tp_richcompare */
2190 0, /* tp_weaklistoffset */
2191 0, /* tp_iter */
2192 0, /* tp_iternext */
2193 0, /* tp_methods */
2194 0, /* tp_members */
2195 0, /* tp_getset */
2196 0, /* tp_base */
2197 0, /* tp_dict */
2198 0, /* tp_descr_get */
2199 0, /* tp_descr_set */
2200 0, /* tp_dictoffset */
2201 0, /* tp_init */
2202 0, /* tp_alloc */
2203 interpid_new, /* tp_new */
2204};
2205
2206static PyObject *
2207_get_id(PyInterpreterState *interp)
2208{
2209 PY_INT64_T id = PyInterpreterState_GetID(interp);
2210 if (id < 0) {
2211 return NULL;
2212 }
2213 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
2214}
2215
2216static PyInterpreterState *
2217_look_up(PyObject *requested_id)
2218{
2219 int64_t id;
2220 if (PyObject_TypeCheck(requested_id, &InterpreterIDtype)) {
2221 id = ((interpid *)requested_id)->id;
2222 }
2223 else {
2224 id = PyLong_AsLongLong(requested_id);
2225 if (id == -1 && PyErr_Occurred() != NULL) {
2226 return NULL;
2227 }
2228 assert(id <= INT64_MAX);
2229 }
2230 return _PyInterpreterState_LookUpID(id);
2231}
2232
Eric Snow7f8bfc92018-01-29 18:23:44 -07002233
2234/* module level code ********************************************************/
2235
2236/* globals is the process-global state for the module. It holds all
2237 the data that we need to share between interpreters, so it cannot
2238 hold PyObject values. */
2239static struct globals {
2240 _channels channels;
2241} _globals = {{0}};
2242
2243static int
2244_init_globals(void)
2245{
2246 if (_channels_init(&_globals.channels) != 0) {
2247 return -1;
2248 }
2249 return 0;
2250}
2251
2252static _channels *
2253_global_channels(void) {
2254 return &_globals.channels;
2255}
2256
2257static PyObject *
2258interp_create(PyObject *self, PyObject *args)
2259{
2260 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
2261 return NULL;
2262 }
2263
2264 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002265 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2266 // XXX Possible GILState issues?
2267 PyThreadState *tstate = Py_NewInterpreter();
Eric Snow7f8bfc92018-01-29 18:23:44 -07002268 PyThreadState_Swap(save_tstate);
2269 if (tstate == NULL) {
2270 /* Since no new thread state was created, there is no exception to
2271 propagate; raise a fresh one after swapping in the old thread
2272 state. */
2273 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2274 return NULL;
2275 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002276 if (_PyInterpreterState_IDInitref(tstate->interp) != 0) {
2277 goto error;
2278 };
Eric Snow7f8bfc92018-01-29 18:23:44 -07002279 return _get_id(tstate->interp);
Eric Snow4c6955e2018-02-16 18:53:40 -07002280
2281error:
Eric Snowf53d9f22018-02-20 16:30:17 -07002282 // XXX Possible GILState issues?
Eric Snow4c6955e2018-02-16 18:53:40 -07002283 save_tstate = PyThreadState_Swap(tstate);
2284 Py_EndInterpreter(tstate);
2285 PyThreadState_Swap(save_tstate);
2286 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002287}
2288
2289PyDoc_STRVAR(create_doc,
2290"create() -> ID\n\
2291\n\
2292Create a new interpreter and return a unique generated ID.");
2293
2294
2295static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002296interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002297{
Eric Snow6d2cd902018-05-16 15:04:57 -04002298 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002299 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002300 // XXX Use "L" for id?
2301 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2302 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002303 return NULL;
2304 }
2305 if (!PyLong_Check(id)) {
2306 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2307 return NULL;
2308 }
2309
2310 // Look up the interpreter.
2311 PyInterpreterState *interp = _look_up(id);
2312 if (interp == NULL) {
2313 return NULL;
2314 }
2315
2316 // Ensure we don't try to destroy the current interpreter.
2317 PyInterpreterState *current = _get_current();
2318 if (current == NULL) {
2319 return NULL;
2320 }
2321 if (interp == current) {
2322 PyErr_SetString(PyExc_RuntimeError,
2323 "cannot destroy the current interpreter");
2324 return NULL;
2325 }
2326
2327 // Ensure the interpreter isn't running.
2328 /* XXX We *could* support destroying a running interpreter but
2329 aren't going to worry about it for now. */
2330 if (_ensure_not_running(interp) < 0) {
2331 return NULL;
2332 }
2333
2334 // Destroy the interpreter.
2335 //PyInterpreterState_Delete(interp);
Eric Snowf53d9f22018-02-20 16:30:17 -07002336 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2337 // XXX Possible GILState issues?
2338 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002339 Py_EndInterpreter(tstate);
2340 PyThreadState_Swap(save_tstate);
2341
2342 Py_RETURN_NONE;
2343}
2344
2345PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002346"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002347\n\
2348Destroy the identified interpreter.\n\
2349\n\
2350Attempting to destroy the current interpreter results in a RuntimeError.\n\
2351So does an unrecognized ID.");
2352
2353
2354static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302355interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002356{
2357 PyObject *ids, *id;
2358 PyInterpreterState *interp;
2359
2360 ids = PyList_New(0);
2361 if (ids == NULL) {
2362 return NULL;
2363 }
2364
2365 interp = PyInterpreterState_Head();
2366 while (interp != NULL) {
2367 id = _get_id(interp);
2368 if (id == NULL) {
2369 Py_DECREF(ids);
2370 return NULL;
2371 }
2372 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002373 int res = PyList_Insert(ids, 0, id);
2374 Py_DECREF(id);
2375 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002376 Py_DECREF(ids);
2377 return NULL;
2378 }
2379
2380 interp = PyInterpreterState_Next(interp);
2381 }
2382
2383 return ids;
2384}
2385
2386PyDoc_STRVAR(list_all_doc,
2387"list_all() -> [ID]\n\
2388\n\
2389Return a list containing the ID of every existing interpreter.");
2390
2391
2392static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302393interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002394{
2395 PyInterpreterState *interp =_get_current();
2396 if (interp == NULL) {
2397 return NULL;
2398 }
2399 return _get_id(interp);
2400}
2401
2402PyDoc_STRVAR(get_current_doc,
2403"get_current() -> ID\n\
2404\n\
2405Return the ID of current interpreter.");
2406
2407
2408static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302409interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002410{
2411 // Currently, 0 is always the main interpreter.
Eric Snow6d2cd902018-05-16 15:04:57 -04002412 PY_INT64_T id = 0;
2413 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002414}
2415
2416PyDoc_STRVAR(get_main_doc,
2417"get_main() -> ID\n\
2418\n\
2419Return the ID of main interpreter.");
2420
2421
2422static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002423interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002424{
Eric Snow6d2cd902018-05-16 15:04:57 -04002425 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002426 PyObject *id, *code;
2427 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002428 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2429 "OU|O:run_string", kwlist,
2430 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002431 return NULL;
2432 }
2433 if (!PyLong_Check(id)) {
2434 PyErr_SetString(PyExc_TypeError, "first arg (ID) must be an int");
2435 return NULL;
2436 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002437
2438 // Look up the interpreter.
2439 PyInterpreterState *interp = _look_up(id);
2440 if (interp == NULL) {
2441 return NULL;
2442 }
2443
2444 // Extract code.
2445 Py_ssize_t size;
2446 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2447 if (codestr == NULL) {
2448 return NULL;
2449 }
2450 if (strlen(codestr) != (size_t)size) {
2451 PyErr_SetString(PyExc_ValueError,
2452 "source code string cannot contain null bytes");
2453 return NULL;
2454 }
2455
2456 // Run the code in the interpreter.
2457 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2458 return NULL;
2459 }
2460 Py_RETURN_NONE;
2461}
2462
2463PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002464"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002465\n\
2466Execute the provided string in the identified interpreter.\n\
2467\n\
2468See PyRun_SimpleStrings.");
2469
2470
2471static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002472object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002473{
Eric Snow6d2cd902018-05-16 15:04:57 -04002474 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002475 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002476 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2477 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002478 return NULL;
2479 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002480
Eric Snow7f8bfc92018-01-29 18:23:44 -07002481 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2482 Py_RETURN_TRUE;
2483 }
2484 PyErr_Clear();
2485 Py_RETURN_FALSE;
2486}
2487
2488PyDoc_STRVAR(is_shareable_doc,
2489"is_shareable(obj) -> bool\n\
2490\n\
2491Return True if the object's data may be shared between interpreters and\n\
2492False otherwise.");
2493
2494
2495static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002496interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002497{
Eric Snow6d2cd902018-05-16 15:04:57 -04002498 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002499 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002500 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2501 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002502 return NULL;
2503 }
2504 if (!PyLong_Check(id)) {
2505 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2506 return NULL;
2507 }
2508
2509 PyInterpreterState *interp = _look_up(id);
2510 if (interp == NULL) {
2511 return NULL;
2512 }
2513 int is_running = _is_running(interp);
2514 if (is_running < 0) {
2515 return NULL;
2516 }
2517 if (is_running) {
2518 Py_RETURN_TRUE;
2519 }
2520 Py_RETURN_FALSE;
2521}
2522
2523PyDoc_STRVAR(is_running_doc,
2524"is_running(id) -> bool\n\
2525\n\
2526Return whether or not the identified interpreter is running.");
2527
2528static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302529channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002530{
2531 int64_t cid = _channel_create(&_globals.channels);
2532 if (cid < 0) {
2533 return NULL;
2534 }
2535 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002536 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002537 if (id == NULL) {
2538 if (_channel_destroy(&_globals.channels, cid) != 0) {
2539 // XXX issue a warning?
2540 }
2541 return NULL;
2542 }
2543 assert(((channelid *)id)->channels != NULL);
2544 return id;
2545}
2546
2547PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002548"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002549\n\
2550Create a new cross-interpreter channel and return a unique generated ID.");
2551
2552static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002553channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002554{
Eric Snow6d2cd902018-05-16 15:04:57 -04002555 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002556 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002557 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2558 "O:channel_destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002559 return NULL;
2560 }
2561 int64_t cid = _coerce_id(id);
2562 if (cid < 0) {
2563 return NULL;
2564 }
2565
2566 if (_channel_destroy(&_globals.channels, cid) != 0) {
2567 return NULL;
2568 }
2569 Py_RETURN_NONE;
2570}
2571
2572PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002573"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002574\n\
2575Close and finalize the channel. Afterward attempts to use the channel\n\
2576will behave as though it never existed.");
2577
2578static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302579channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002580{
2581 int64_t count = 0;
2582 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2583 if (cids == NULL) {
2584 if (count == 0) {
2585 return PyList_New(0);
2586 }
2587 return NULL;
2588 }
2589 PyObject *ids = PyList_New((Py_ssize_t)count);
2590 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002591 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002592 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002593 int64_t *cur = cids;
2594 for (int64_t i=0; i < count; cur++, i++) {
2595 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002596 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002597 if (id == NULL) {
2598 Py_DECREF(ids);
2599 ids = NULL;
2600 break;
2601 }
2602 PyList_SET_ITEM(ids, i, id);
2603 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002604
2605finally:
2606 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002607 return ids;
2608}
2609
2610PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002611"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002612\n\
2613Return the list of all IDs for active channels.");
2614
2615static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002616channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002617{
Eric Snow6d2cd902018-05-16 15:04:57 -04002618 static char *kwlist[] = {"cid", "obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002619 PyObject *id;
2620 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002621 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2622 "OO:channel_send", kwlist, &id, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002623 return NULL;
2624 }
2625 int64_t cid = _coerce_id(id);
2626 if (cid < 0) {
2627 return NULL;
2628 }
2629
2630 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2631 return NULL;
2632 }
2633 Py_RETURN_NONE;
2634}
2635
2636PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002637"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002638\n\
2639Add the object's data to the channel's queue.");
2640
2641static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002642channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002643{
Eric Snow6d2cd902018-05-16 15:04:57 -04002644 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002645 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002646 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2647 "O:channel_recv", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002648 return NULL;
2649 }
2650 int64_t cid = _coerce_id(id);
2651 if (cid < 0) {
2652 return NULL;
2653 }
2654
2655 return _channel_recv(&_globals.channels, cid);
2656}
2657
2658PyDoc_STRVAR(channel_recv_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002659"channel_recv(cid) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002660\n\
2661Return a new object from the data at the from of the channel's queue.");
2662
2663static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002664channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002665{
Eric Snow6d2cd902018-05-16 15:04:57 -04002666 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
2667 PyObject *id;
2668 int send = 0;
2669 int recv = 0;
2670 int force = 0;
2671 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2672 "O|$ppp:channel_close", kwlist,
2673 &id, &send, &recv, &force)) {
2674 return NULL;
2675 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002676 int64_t cid = _coerce_id(id);
2677 if (cid < 0) {
2678 return NULL;
2679 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002680
Eric Snow3ab01362018-05-17 10:27:09 -04002681 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002682 return NULL;
2683 }
2684 Py_RETURN_NONE;
2685}
2686
2687PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002688"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002689\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002690Close the channel for all interpreters.\n\
2691\n\
2692If the channel is empty then the keyword args are ignored and both\n\
2693ends are immediately closed. Otherwise, if 'force' is True then\n\
2694all queued items are released and both ends are immediately\n\
2695closed.\n\
2696\n\
2697If the channel is not empty *and* 'force' is False then following\n\
2698happens:\n\
2699\n\
2700 * recv is True (regardless of send):\n\
2701 - raise ChannelNotEmptyError\n\
2702 * recv is None and send is None:\n\
2703 - raise ChannelNotEmptyError\n\
2704 * send is True and recv is not True:\n\
2705 - fully close the 'send' end\n\
2706 - close the 'recv' end to interpreters not already receiving\n\
2707 - fully close it once empty\n\
2708\n\
2709Closing an already closed channel results in a ChannelClosedError.\n\
2710\n\
2711Once the channel's ID has no more ref counts in any interpreter\n\
2712the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002713
2714static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002715channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002716{
2717 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002718 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002719 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002720 int send = 0;
2721 int recv = 0;
2722 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002723 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04002724 "O|$ppp:channel_release", kwlist,
2725 &id, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002726 return NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002727 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002728 int64_t cid = _coerce_id(id);
2729 if (cid < 0) {
2730 return NULL;
2731 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002732 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002733 send = 1;
2734 recv = 1;
2735 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002736
2737 // XXX Handle force is True.
2738 // XXX Fix implicit release.
2739
Eric Snow7f8bfc92018-01-29 18:23:44 -07002740 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2741 return NULL;
2742 }
2743 Py_RETURN_NONE;
2744}
2745
Eric Snow6d2cd902018-05-16 15:04:57 -04002746PyDoc_STRVAR(channel_release_doc,
2747"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002748\n\
2749Close the channel for the current interpreter. 'send' and 'recv'\n\
2750(bool) may be used to indicate the ends to close. By default both\n\
2751ends are closed. Closing an already closed end is a noop.");
2752
2753static PyObject *
2754channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2755{
2756 return channelid_new(&ChannelIDtype, args, kwds);
2757}
2758
2759static PyMethodDef module_functions[] = {
2760 {"create", (PyCFunction)interp_create,
2761 METH_VARARGS, create_doc},
2762 {"destroy", (PyCFunction)interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002763 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302764 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002765 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302766 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002767 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302768 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002769 METH_NOARGS, get_main_doc},
2770 {"is_running", (PyCFunction)interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002771 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002772 {"run_string", (PyCFunction)interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002773 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002774
2775 {"is_shareable", (PyCFunction)object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002776 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002777
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302778 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002779 METH_NOARGS, channel_create_doc},
2780 {"channel_destroy", (PyCFunction)channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002781 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302782 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002783 METH_NOARGS, channel_list_all_doc},
2784 {"channel_send", (PyCFunction)channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002785 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002786 {"channel_recv", (PyCFunction)channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002787 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
2788 {"channel_close", (PyCFunction)channel_close,
2789 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
2790 {"channel_release", (PyCFunction)channel_release,
2791 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002792 {"_channel_id", (PyCFunction)channel__channel_id,
2793 METH_VARARGS | METH_KEYWORDS, NULL},
2794
2795 {NULL, NULL} /* sentinel */
2796};
2797
2798
2799/* initialization function */
2800
2801PyDoc_STRVAR(module_doc,
2802"This module provides primitive operations to manage Python interpreters.\n\
2803The 'interpreters' module provides a more convenient interface.");
2804
2805static struct PyModuleDef interpretersmodule = {
2806 PyModuleDef_HEAD_INIT,
2807 "_xxsubinterpreters", /* m_name */
2808 module_doc, /* m_doc */
2809 -1, /* m_size */
2810 module_functions, /* m_methods */
2811 NULL, /* m_slots */
2812 NULL, /* m_traverse */
2813 NULL, /* m_clear */
2814 NULL /* m_free */
2815};
2816
2817
2818PyMODINIT_FUNC
2819PyInit__xxsubinterpreters(void)
2820{
2821 if (_init_globals() != 0) {
2822 return NULL;
2823 }
2824
2825 /* Initialize types */
2826 ChannelIDtype.tp_base = &PyLong_Type;
2827 if (PyType_Ready(&ChannelIDtype) != 0) {
2828 return NULL;
2829 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002830 InterpreterIDtype.tp_base = &PyLong_Type;
2831 if (PyType_Ready(&InterpreterIDtype) != 0) {
2832 return NULL;
2833 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002834
2835 /* Create the module */
2836 PyObject *module = PyModule_Create(&interpretersmodule);
2837 if (module == NULL) {
2838 return NULL;
2839 }
2840
2841 /* Add exception types */
2842 PyObject *ns = PyModule_GetDict(module); // borrowed
2843 if (interp_exceptions_init(ns) != 0) {
2844 return NULL;
2845 }
2846 if (channel_exceptions_init(ns) != 0) {
2847 return NULL;
2848 }
2849
2850 /* Add other types */
2851 Py_INCREF(&ChannelIDtype);
2852 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2853 return NULL;
2854 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002855 Py_INCREF(&InterpreterIDtype);
2856 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&InterpreterIDtype) != 0) {
2857 return NULL;
2858 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002859
2860 if (_PyCrossInterpreterData_Register_Class(&ChannelIDtype, _channelid_shared)) {
2861 return NULL;
2862 }
2863
2864 return module;
2865}