blob: 8567e4fd970c6a2c7c5703993341ee887cd36cce [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
Eric Snow6854e802018-06-01 16:26:01 -060036_coerce_id(PyObject *orig)
Eric Snow7f8bfc92018-01-29 18:23:44 -070037{
Eric Snow6854e802018-06-01 16:26:01 -060038 PyObject *pyid = PyNumber_Long(orig);
39 if (pyid == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -070040 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
Eric Snow6854e802018-06-01 16:26:01 -060041 PyErr_Format(PyExc_TypeError,
42 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070043 }
44 else {
Eric Snow6854e802018-06-01 16:26:01 -060045 PyErr_Format(PyExc_ValueError,
46 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070047 }
48 return -1;
49 }
Eric Snow6854e802018-06-01 16:26:01 -060050 int64_t id = PyLong_AsLongLong(pyid);
51 Py_DECREF(pyid);
52 if (id == -1 && PyErr_Occurred() != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070053 if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
Eric Snow6854e802018-06-01 16:26:01 -060054 PyErr_Format(PyExc_ValueError,
55 "'id' must be a non-negative int, got %R", orig);
Eric Snow4e9da0d2018-02-02 21:49:49 -070056 }
Eric Snow7f8bfc92018-01-29 18:23:44 -070057 return -1;
58 }
Eric Snow6854e802018-06-01 16:26:01 -060059 if (id < 0) {
60 PyErr_Format(PyExc_ValueError,
61 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070062 return -1;
63 }
Eric Snow6854e802018-06-01 16:26:01 -060064 return id;
Eric Snow7f8bfc92018-01-29 18:23:44 -070065}
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) {
Eric Snowab4a1982018-06-13 08:02:39 -06001003 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001004 goto done;
1005 }
1006 if (ref->chan == NULL || !ref->chan->open) {
Eric Snowab4a1982018-06-13 08:02:39 -06001007 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001008 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) {
Eric Snowab4a1982018-06-13 08:02:39 -06001067 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001068 goto done;
1069 }
1070
1071 if (ref->chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001072 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001073 goto done;
1074 }
Eric Snow3ab01362018-05-17 10:27:09 -04001075 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001076 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001077 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) {
Eric Snow6854e802018-06-01 16:26:01 -06001084 PyErr_Format(ChannelClosedError,
Eric Snowab4a1982018-06-13 08:02:39 -06001085 "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001086 goto done;
1087 }
1088 // Mark the channel as closing and return. The channel
1089 // will be cleaned up in _channel_next().
1090 PyErr_Clear();
1091 if (_channel_set_closing(ref, channels->mutex) != 0) {
1092 goto done;
1093 }
1094 if (pchan != NULL) {
1095 *pchan = ref->chan;
1096 }
1097 res = 0;
1098 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001099 goto done;
1100 }
1101 if (pchan != NULL) {
1102 *pchan = ref->chan;
1103 }
Eric Snow3ab01362018-05-17 10:27:09 -04001104 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001105 _channel_free(ref->chan);
1106 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001107 ref->chan = NULL;
1108 }
1109
1110 res = 0;
1111done:
1112 PyThread_release_lock(channels->mutex);
1113 return res;
1114}
1115
1116static void
1117_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1118 _PyChannelState **pchan)
1119{
1120 if (ref == channels->head) {
1121 channels->head = ref->next;
1122 }
1123 else {
1124 prev->next = ref->next;
1125 }
1126 channels->numopen -= 1;
1127
1128 if (pchan != NULL) {
1129 *pchan = ref->chan;
1130 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001131 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001132}
1133
1134static int
1135_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1136{
1137 int res = -1;
1138 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1139
1140 if (pchan != NULL) {
1141 *pchan = NULL;
1142 }
1143
1144 _channelref *prev = NULL;
1145 _channelref *ref = _channelref_find(channels->head, id, &prev);
1146 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001147 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001148 goto done;
1149 }
1150
1151 _channels_remove_ref(channels, ref, prev, pchan);
1152
1153 res = 0;
1154done:
1155 PyThread_release_lock(channels->mutex);
1156 return res;
1157}
1158
1159static int
1160_channels_add_id_object(_channels *channels, int64_t id)
1161{
1162 int res = -1;
1163 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1164
1165 _channelref *ref = _channelref_find(channels->head, id, NULL);
1166 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001167 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001168 goto done;
1169 }
1170 ref->objcount += 1;
1171
1172 res = 0;
1173done:
1174 PyThread_release_lock(channels->mutex);
1175 return res;
1176}
1177
1178static void
1179_channels_drop_id_object(_channels *channels, int64_t id)
1180{
1181 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1182
1183 _channelref *prev = NULL;
1184 _channelref *ref = _channelref_find(channels->head, id, &prev);
1185 if (ref == NULL) {
1186 // Already destroyed.
1187 goto done;
1188 }
1189 ref->objcount -= 1;
1190
1191 // Destroy if no longer used.
1192 if (ref->objcount == 0) {
1193 _PyChannelState *chan = NULL;
1194 _channels_remove_ref(channels, ref, prev, &chan);
1195 if (chan != NULL) {
1196 _channel_free(chan);
1197 }
1198 }
1199
1200done:
1201 PyThread_release_lock(channels->mutex);
1202}
1203
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001204static int64_t *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001205_channels_list_all(_channels *channels, int64_t *count)
1206{
1207 int64_t *cids = NULL;
1208 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1209 int64_t numopen = channels->numopen;
1210 if (numopen >= PY_SSIZE_T_MAX) {
1211 PyErr_SetString(PyExc_RuntimeError, "too many channels open");
1212 goto done;
1213 }
1214 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
1215 if (ids == NULL) {
1216 goto done;
1217 }
1218 _channelref *ref = channels->head;
1219 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
1220 ids[i] = ref->id;
1221 }
1222 *count = channels->numopen;
1223
1224 cids = ids;
1225done:
1226 PyThread_release_lock(channels->mutex);
1227 return cids;
1228}
1229
Eric Snow3ab01362018-05-17 10:27:09 -04001230/* support for closing non-empty channels */
1231
1232struct _channel_closing {
1233 struct _channelref *ref;
1234};
1235
1236static int
1237_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
1238 struct _channel *chan = ref->chan;
1239 if (chan == NULL) {
1240 // already closed
1241 return 0;
1242 }
1243 int res = -1;
1244 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1245 if (chan->closing != NULL) {
1246 PyErr_SetString(ChannelClosedError, "channel closed");
1247 goto done;
1248 }
1249 chan->closing = PyMem_NEW(struct _channel_closing, 1);
1250 if (chan->closing == NULL) {
1251 goto done;
1252 }
1253 chan->closing->ref = ref;
1254
1255 res = 0;
1256done:
1257 PyThread_release_lock(chan->mutex);
1258 return res;
1259}
1260
1261static void
1262_channel_clear_closing(struct _channel *chan) {
1263 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1264 if (chan->closing != NULL) {
1265 PyMem_Free(chan->closing);
1266 chan->closing = NULL;
1267 }
1268 PyThread_release_lock(chan->mutex);
1269}
1270
1271static void
1272_channel_finish_closing(struct _channel *chan) {
1273 struct _channel_closing *closing = chan->closing;
1274 if (closing == NULL) {
1275 return;
1276 }
1277 _channelref *ref = closing->ref;
1278 _channel_clear_closing(chan);
1279 // Do the things that would have been done in _channels_close().
1280 ref->chan = NULL;
1281 _channel_free(chan);
1282};
1283
Eric Snow7f8bfc92018-01-29 18:23:44 -07001284/* "high"-level channel-related functions */
1285
1286static int64_t
1287_channel_create(_channels *channels)
1288{
1289 _PyChannelState *chan = _channel_new();
1290 if (chan == NULL) {
1291 return -1;
1292 }
1293 int64_t id = _channels_add(channels, chan);
1294 if (id < 0) {
1295 _channel_free(chan);
1296 return -1;
1297 }
1298 return id;
1299}
1300
1301static int
1302_channel_destroy(_channels *channels, int64_t id)
1303{
1304 _PyChannelState *chan = NULL;
1305 if (_channels_remove(channels, id, &chan) != 0) {
1306 return -1;
1307 }
1308 if (chan != NULL) {
1309 _channel_free(chan);
1310 }
1311 return 0;
1312}
1313
1314static int
1315_channel_send(_channels *channels, int64_t id, PyObject *obj)
1316{
1317 PyInterpreterState *interp = _get_current();
1318 if (interp == NULL) {
1319 return -1;
1320 }
1321
1322 // Look up the channel.
1323 PyThread_type_lock mutex = NULL;
1324 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1325 if (chan == NULL) {
1326 return -1;
1327 }
1328 // Past this point we are responsible for releasing the mutex.
1329
Eric Snow3ab01362018-05-17 10:27:09 -04001330 if (chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001331 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow3ab01362018-05-17 10:27:09 -04001332 PyThread_release_lock(mutex);
1333 return -1;
1334 }
1335
Eric Snow7f8bfc92018-01-29 18:23:44 -07001336 // Convert the object to cross-interpreter data.
1337 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
1338 if (data == NULL) {
1339 PyThread_release_lock(mutex);
1340 return -1;
1341 }
1342 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
1343 PyThread_release_lock(mutex);
1344 return -1;
1345 }
1346
1347 // Add the data to the channel.
1348 int res = _channel_add(chan, interp->id, data);
1349 PyThread_release_lock(mutex);
1350 if (res != 0) {
1351 _PyCrossInterpreterData_Release(data);
1352 PyMem_Free(data);
1353 return -1;
1354 }
1355
1356 return 0;
1357}
1358
1359static PyObject *
1360_channel_recv(_channels *channels, int64_t id)
1361{
1362 PyInterpreterState *interp = _get_current();
1363 if (interp == NULL) {
1364 return NULL;
1365 }
1366
1367 // Look up the channel.
1368 PyThread_type_lock mutex = NULL;
1369 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1370 if (chan == NULL) {
1371 return NULL;
1372 }
1373 // Past this point we are responsible for releasing the mutex.
1374
1375 // Pop off the next item from the channel.
1376 _PyCrossInterpreterData *data = _channel_next(chan, interp->id);
1377 PyThread_release_lock(mutex);
1378 if (data == NULL) {
Eric Snow6d2cd902018-05-16 15:04:57 -04001379 if (!PyErr_Occurred()) {
Eric Snowab4a1982018-06-13 08:02:39 -06001380 PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001381 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001382 return NULL;
1383 }
1384
1385 // Convert the data back to an object.
1386 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
1387 if (obj == NULL) {
1388 return NULL;
1389 }
1390 _PyCrossInterpreterData_Release(data);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001391 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001392
1393 return obj;
1394}
1395
1396static int
1397_channel_drop(_channels *channels, int64_t id, int send, int recv)
1398{
1399 PyInterpreterState *interp = _get_current();
1400 if (interp == NULL) {
1401 return -1;
1402 }
1403
1404 // Look up the channel.
1405 PyThread_type_lock mutex = NULL;
1406 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1407 if (chan == NULL) {
1408 return -1;
1409 }
1410 // Past this point we are responsible for releasing the mutex.
1411
1412 // Close one or both of the two ends.
Eric Snow4e9da0d2018-02-02 21:49:49 -07001413 int res = _channel_close_interpreter(chan, interp->id, send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001414 PyThread_release_lock(mutex);
1415 return res;
1416}
1417
1418static int
Eric Snow3ab01362018-05-17 10:27:09 -04001419_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001420{
Eric Snow3ab01362018-05-17 10:27:09 -04001421 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001422}
1423
1424/* ChannelID class */
1425
Eric Snow7f8bfc92018-01-29 18:23:44 -07001426static PyTypeObject ChannelIDtype;
1427
1428typedef struct channelid {
1429 PyObject_HEAD
1430 int64_t id;
1431 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001432 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001433 _channels *channels;
1434} channelid;
1435
1436static channelid *
1437newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001438 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001439{
1440 channelid *self = PyObject_New(channelid, cls);
1441 if (self == NULL) {
1442 return NULL;
1443 }
1444 self->id = cid;
1445 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001446 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001447 self->channels = channels;
1448
1449 if (_channels_add_id_object(channels, cid) != 0) {
1450 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1451 PyErr_Clear();
1452 }
1453 else {
1454 Py_DECREF((PyObject *)self);
1455 return NULL;
1456 }
1457 }
1458
1459 return self;
1460}
1461
1462static _channels * _global_channels(void);
1463
1464static PyObject *
1465channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1466{
Eric Snow6d2cd902018-05-16 15:04:57 -04001467 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07001468 PyObject *id;
1469 int send = -1;
1470 int recv = -1;
1471 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001472 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001473 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04001474 "O|$pppp:ChannelID.__new__", kwlist,
1475 &id, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001476 return NULL;
1477
1478 // Coerce and check the ID.
1479 int64_t cid;
1480 if (PyObject_TypeCheck(id, &ChannelIDtype)) {
1481 cid = ((channelid *)id)->id;
1482 }
1483 else {
1484 cid = _coerce_id(id);
1485 if (cid < 0) {
1486 return NULL;
1487 }
1488 }
1489
1490 // Handle "send" and "recv".
1491 if (send == 0 && recv == 0) {
1492 PyErr_SetString(PyExc_ValueError,
1493 "'send' and 'recv' cannot both be False");
1494 return NULL;
1495 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001496
Eric Snow7f8bfc92018-01-29 18:23:44 -07001497 int end = 0;
1498 if (send == 1) {
1499 if (recv == 0 || recv == -1) {
1500 end = CHANNEL_SEND;
1501 }
1502 }
1503 else if (recv == 1) {
1504 end = CHANNEL_RECV;
1505 }
1506
Eric Snow6d2cd902018-05-16 15:04:57 -04001507 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
1508 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001509}
1510
1511static void
1512channelid_dealloc(PyObject *v)
1513{
1514 int64_t cid = ((channelid *)v)->id;
1515 _channels *channels = ((channelid *)v)->channels;
1516 Py_TYPE(v)->tp_free(v);
1517
1518 _channels_drop_id_object(channels, cid);
1519}
1520
1521static PyObject *
1522channelid_repr(PyObject *self)
1523{
1524 PyTypeObject *type = Py_TYPE(self);
1525 const char *name = _PyType_Name(type);
1526
1527 channelid *cid = (channelid *)self;
1528 const char *fmt;
1529 if (cid->end == CHANNEL_SEND) {
Eric Snowab4a1982018-06-13 08:02:39 -06001530 fmt = "%s(%" PRId64 ", send=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001531 }
1532 else if (cid->end == CHANNEL_RECV) {
Eric Snowab4a1982018-06-13 08:02:39 -06001533 fmt = "%s(%" PRId64 ", recv=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001534 }
1535 else {
Eric Snowab4a1982018-06-13 08:02:39 -06001536 fmt = "%s(%" PRId64 ")";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001537 }
1538 return PyUnicode_FromFormat(fmt, name, cid->id);
1539}
1540
Eric Snow6d2cd902018-05-16 15:04:57 -04001541static PyObject *
1542channelid_str(PyObject *self)
1543{
1544 channelid *cid = (channelid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06001545 return PyUnicode_FromFormat("%" PRId64 "", cid->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001546}
1547
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001548static PyObject *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001549channelid_int(PyObject *self)
1550{
1551 channelid *cid = (channelid *)self;
1552 return PyLong_FromLongLong(cid->id);
1553}
1554
1555static PyNumberMethods channelid_as_number = {
1556 0, /* nb_add */
1557 0, /* nb_subtract */
1558 0, /* nb_multiply */
1559 0, /* nb_remainder */
1560 0, /* nb_divmod */
1561 0, /* nb_power */
1562 0, /* nb_negative */
1563 0, /* nb_positive */
1564 0, /* nb_absolute */
1565 0, /* nb_bool */
1566 0, /* nb_invert */
1567 0, /* nb_lshift */
1568 0, /* nb_rshift */
1569 0, /* nb_and */
1570 0, /* nb_xor */
1571 0, /* nb_or */
1572 (unaryfunc)channelid_int, /* nb_int */
1573 0, /* nb_reserved */
1574 0, /* nb_float */
1575
1576 0, /* nb_inplace_add */
1577 0, /* nb_inplace_subtract */
1578 0, /* nb_inplace_multiply */
1579 0, /* nb_inplace_remainder */
1580 0, /* nb_inplace_power */
1581 0, /* nb_inplace_lshift */
1582 0, /* nb_inplace_rshift */
1583 0, /* nb_inplace_and */
1584 0, /* nb_inplace_xor */
1585 0, /* nb_inplace_or */
1586
1587 0, /* nb_floor_divide */
1588 0, /* nb_true_divide */
1589 0, /* nb_inplace_floor_divide */
1590 0, /* nb_inplace_true_divide */
1591
1592 (unaryfunc)channelid_int, /* nb_index */
1593};
1594
1595static Py_hash_t
1596channelid_hash(PyObject *self)
1597{
1598 channelid *cid = (channelid *)self;
1599 PyObject *id = PyLong_FromLongLong(cid->id);
1600 if (id == NULL) {
1601 return -1;
1602 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001603 Py_hash_t hash = PyObject_Hash(id);
1604 Py_DECREF(id);
1605 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001606}
1607
1608static PyObject *
1609channelid_richcompare(PyObject *self, PyObject *other, int op)
1610{
1611 if (op != Py_EQ && op != Py_NE) {
1612 Py_RETURN_NOTIMPLEMENTED;
1613 }
1614
1615 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1616 Py_RETURN_NOTIMPLEMENTED;
1617 }
1618
1619 channelid *cid = (channelid *)self;
1620 int equal;
1621 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1622 channelid *othercid = (channelid *)other;
1623 if (cid->end != othercid->end) {
1624 equal = 0;
1625 }
1626 else {
1627 equal = (cid->id == othercid->id);
1628 }
1629 }
1630 else {
1631 other = PyNumber_Long(other);
1632 if (other == NULL) {
1633 PyErr_Clear();
1634 Py_RETURN_NOTIMPLEMENTED;
1635 }
1636 int64_t othercid = PyLong_AsLongLong(other);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001637 Py_DECREF(other);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001638 if (othercid == -1 && PyErr_Occurred() != NULL) {
1639 return NULL;
1640 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001641 if (othercid < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001642 equal = 0;
1643 }
1644 else {
1645 equal = (cid->id == othercid);
1646 }
1647 }
1648
1649 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1650 Py_RETURN_TRUE;
1651 }
1652 Py_RETURN_FALSE;
1653}
1654
Eric Snowab4a1982018-06-13 08:02:39 -06001655static PyObject *
1656_channel_from_cid(PyObject *cid, int end)
1657{
1658 PyObject *highlevel = PyImport_ImportModule("interpreters");
1659 if (highlevel == NULL) {
1660 PyErr_Clear();
1661 highlevel = PyImport_ImportModule("test.support.interpreters");
1662 if (highlevel == NULL) {
1663 return NULL;
1664 }
1665 }
1666 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
1667 "SendChannel";
1668 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1669 Py_DECREF(highlevel);
1670 if (cls == NULL) {
1671 return NULL;
1672 }
1673 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1674 Py_DECREF(cls);
1675 if (chan == NULL) {
1676 return NULL;
1677 }
1678 return chan;
1679}
1680
Eric Snow7f8bfc92018-01-29 18:23:44 -07001681struct _channelid_xid {
1682 int64_t id;
1683 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001684 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001685};
1686
1687static PyObject *
1688_channelid_from_xid(_PyCrossInterpreterData *data)
1689{
1690 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001691 // Note that we do not preserve the "resolve" flag.
1692 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1693 _global_channels(), 0, 0);
1694 if (xid->end == 0) {
1695 return cid;
1696 }
1697 if (!xid->resolve) {
1698 return cid;
1699 }
1700
1701 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06001702 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04001703 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001704 PyErr_Clear();
1705 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04001706 }
1707 Py_DECREF(cid);
1708 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001709}
1710
1711static int
1712_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1713{
1714 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1715 if (xid == NULL) {
1716 return -1;
1717 }
1718 xid->id = ((channelid *)obj)->id;
1719 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001720 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001721
1722 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06001723 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001724 data->obj = obj;
1725 data->new_object = _channelid_from_xid;
1726 data->free = PyMem_Free;
1727 return 0;
1728}
1729
1730static PyObject *
1731channelid_end(PyObject *self, void *end)
1732{
1733 int force = 1;
1734 channelid *cid = (channelid *)self;
1735 if (end != NULL) {
1736 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001737 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001738 }
1739
1740 if (cid->end == CHANNEL_SEND) {
1741 return PyUnicode_InternFromString("send");
1742 }
1743 if (cid->end == CHANNEL_RECV) {
1744 return PyUnicode_InternFromString("recv");
1745 }
1746 return PyUnicode_InternFromString("both");
1747}
1748
1749static int _channelid_end_send = CHANNEL_SEND;
1750static int _channelid_end_recv = CHANNEL_RECV;
1751
1752static PyGetSetDef channelid_getsets[] = {
1753 {"end", (getter)channelid_end, NULL,
1754 PyDoc_STR("'send', 'recv', or 'both'")},
1755 {"send", (getter)channelid_end, NULL,
1756 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1757 {"recv", (getter)channelid_end, NULL,
1758 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1759 {NULL}
1760};
1761
1762PyDoc_STRVAR(channelid_doc,
1763"A channel ID identifies a channel and may be used as an int.");
1764
1765static PyTypeObject ChannelIDtype = {
1766 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1767 "_xxsubinterpreters.ChannelID", /* tp_name */
1768 sizeof(channelid), /* tp_size */
1769 0, /* tp_itemsize */
1770 (destructor)channelid_dealloc, /* tp_dealloc */
1771 0, /* tp_print */
1772 0, /* tp_getattr */
1773 0, /* tp_setattr */
1774 0, /* tp_as_async */
1775 (reprfunc)channelid_repr, /* tp_repr */
1776 &channelid_as_number, /* tp_as_number */
1777 0, /* tp_as_sequence */
1778 0, /* tp_as_mapping */
1779 channelid_hash, /* tp_hash */
1780 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001781 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001782 0, /* tp_getattro */
1783 0, /* tp_setattro */
1784 0, /* tp_as_buffer */
1785 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1786 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
1787 channelid_doc, /* tp_doc */
1788 0, /* tp_traverse */
1789 0, /* tp_clear */
1790 channelid_richcompare, /* tp_richcompare */
1791 0, /* tp_weaklistoffset */
1792 0, /* tp_iter */
1793 0, /* tp_iternext */
1794 0, /* tp_methods */
1795 0, /* tp_members */
1796 channelid_getsets, /* tp_getset */
1797 0, /* tp_base */
1798 0, /* tp_dict */
1799 0, /* tp_descr_get */
1800 0, /* tp_descr_set */
1801 0, /* tp_dictoffset */
1802 0, /* tp_init */
1803 0, /* tp_alloc */
1804 // Note that we do not set tp_new to channelid_new. Instead we
1805 // set it to NULL, meaning it cannot be instantiated from Python
1806 // code. We do this because there is a strong relationship between
1807 // channel IDs and the channel lifecycle, so this limitation avoids
1808 // related complications.
1809 NULL, /* tp_new */
1810};
1811
Eric Snow4e9da0d2018-02-02 21:49:49 -07001812
1813/* interpreter-specific code ************************************************/
1814
1815static PyObject * RunFailedError = NULL;
1816
1817static int
1818interp_exceptions_init(PyObject *ns)
1819{
1820 // XXX Move the exceptions into per-module memory?
1821
1822 if (RunFailedError == NULL) {
1823 // An uncaught exception came out of interp_run_string().
1824 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1825 PyExc_RuntimeError, NULL);
1826 if (RunFailedError == NULL) {
1827 return -1;
1828 }
1829 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1830 return -1;
1831 }
1832 }
1833
1834 return 0;
1835}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001836
Eric Snow7f8bfc92018-01-29 18:23:44 -07001837static int
1838_is_running(PyInterpreterState *interp)
1839{
1840 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1841 if (PyThreadState_Next(tstate) != NULL) {
1842 PyErr_SetString(PyExc_RuntimeError,
1843 "interpreter has more than one thread");
1844 return -1;
1845 }
1846 PyFrameObject *frame = tstate->frame;
1847 if (frame == NULL) {
1848 if (PyErr_Occurred() != NULL) {
1849 return -1;
1850 }
1851 return 0;
1852 }
1853 return (int)(frame->f_executing);
1854}
1855
1856static int
1857_ensure_not_running(PyInterpreterState *interp)
1858{
1859 int is_running = _is_running(interp);
1860 if (is_running < 0) {
1861 return -1;
1862 }
1863 if (is_running) {
1864 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1865 return -1;
1866 }
1867 return 0;
1868}
1869
1870static int
1871_run_script(PyInterpreterState *interp, const char *codestr,
Eric Snow4e9da0d2018-02-02 21:49:49 -07001872 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001873{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001874 PyObject *exctype = NULL;
1875 PyObject *excval = NULL;
1876 PyObject *tb = NULL;
1877
Eric Snow7f8bfc92018-01-29 18:23:44 -07001878 PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
1879 if (main_mod == NULL) {
1880 goto error;
1881 }
1882 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1883 Py_DECREF(main_mod);
1884 if (ns == NULL) {
1885 goto error;
1886 }
1887 Py_INCREF(ns);
1888
1889 // Apply the cross-interpreter data.
1890 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001891 if (_sharedns_apply(shared, ns) != 0) {
1892 Py_DECREF(ns);
1893 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001894 }
1895 }
1896
1897 // Run the string (see PyRun_SimpleStringFlags).
1898 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1899 Py_DECREF(ns);
1900 if (result == NULL) {
1901 goto error;
1902 }
1903 else {
1904 Py_DECREF(result); // We throw away the result.
1905 }
1906
Eric Snow4e9da0d2018-02-02 21:49:49 -07001907 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001908 return 0;
1909
1910error:
Eric Snow4e9da0d2018-02-02 21:49:49 -07001911 PyErr_Fetch(&exctype, &excval, &tb);
1912
1913 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1914 Py_XDECREF(exctype);
1915 Py_XDECREF(excval);
1916 Py_XDECREF(tb);
1917 if (sharedexc == NULL) {
1918 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1919 PyErr_Clear();
1920 sharedexc = NULL;
1921 }
1922 else {
1923 assert(!PyErr_Occurred());
1924 }
1925 *exc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001926 return -1;
1927}
1928
1929static int
1930_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1931 PyObject *shareables)
1932{
1933 if (_ensure_not_running(interp) < 0) {
1934 return -1;
1935 }
1936
Eric Snow4e9da0d2018-02-02 21:49:49 -07001937 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001938 if (shared == NULL && PyErr_Occurred()) {
1939 return -1;
1940 }
1941
1942 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001943 PyThreadState *save_tstate = NULL;
1944 if (interp != PyThreadState_Get()->interp) {
1945 // XXX Using the "head" thread isn't strictly correct.
1946 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1947 // XXX Possible GILState issues?
1948 save_tstate = PyThreadState_Swap(tstate);
1949 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001950
1951 // Run the script.
1952 _sharedexception *exc = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001953 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001954
1955 // Switch back.
1956 if (save_tstate != NULL) {
1957 PyThreadState_Swap(save_tstate);
1958 }
1959
1960 // Propagate any exception out to the caller.
1961 if (exc != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001962 _sharedexception_apply(exc, RunFailedError);
1963 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001964 }
1965 else if (result != 0) {
1966 // We were unable to allocate a shared exception.
1967 PyErr_NoMemory();
1968 }
1969
1970 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001971 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001972 }
1973
1974 return result;
1975}
1976
Eric Snow4c6955e2018-02-16 18:53:40 -07001977/* InterpreterID class */
1978
1979static PyTypeObject InterpreterIDtype;
1980
1981typedef struct interpid {
1982 PyObject_HEAD
1983 int64_t id;
1984} interpid;
1985
1986static interpid *
1987newinterpid(PyTypeObject *cls, int64_t id, int force)
1988{
1989 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
1990 if (interp == NULL) {
1991 if (force) {
1992 PyErr_Clear();
1993 }
1994 else {
1995 return NULL;
1996 }
1997 }
1998
1999 interpid *self = PyObject_New(interpid, cls);
2000 if (self == NULL) {
2001 return NULL;
2002 }
2003 self->id = id;
2004
2005 if (interp != NULL) {
2006 _PyInterpreterState_IDIncref(interp);
2007 }
2008 return self;
2009}
2010
2011static PyObject *
2012interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
2013{
2014 static char *kwlist[] = {"id", "force", NULL};
2015 PyObject *idobj;
2016 int force = 0;
2017 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2018 "O|$p:InterpreterID.__init__", kwlist,
2019 &idobj, &force)) {
2020 return NULL;
2021 }
2022
2023 // Coerce and check the ID.
2024 int64_t id;
2025 if (PyObject_TypeCheck(idobj, &InterpreterIDtype)) {
2026 id = ((interpid *)idobj)->id;
2027 }
2028 else {
2029 id = _coerce_id(idobj);
2030 if (id < 0) {
2031 return NULL;
2032 }
2033 }
2034
2035 return (PyObject *)newinterpid(cls, id, force);
2036}
2037
2038static void
2039interpid_dealloc(PyObject *v)
2040{
2041 int64_t id = ((interpid *)v)->id;
2042 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
2043 if (interp != NULL) {
2044 _PyInterpreterState_IDDecref(interp);
2045 }
2046 else {
2047 // already deleted
2048 PyErr_Clear();
2049 }
2050 Py_TYPE(v)->tp_free(v);
2051}
2052
2053static PyObject *
2054interpid_repr(PyObject *self)
2055{
2056 PyTypeObject *type = Py_TYPE(self);
2057 const char *name = _PyType_Name(type);
2058 interpid *id = (interpid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06002059 return PyUnicode_FromFormat("%s(%" PRId64 ")", name, id->id);
Eric Snow4c6955e2018-02-16 18:53:40 -07002060}
2061
Eric Snow6d2cd902018-05-16 15:04:57 -04002062static PyObject *
2063interpid_str(PyObject *self)
2064{
2065 interpid *id = (interpid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06002066 return PyUnicode_FromFormat("%" PRId64 "", id->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04002067}
2068
Eric Snow4c6955e2018-02-16 18:53:40 -07002069PyObject *
2070interpid_int(PyObject *self)
2071{
2072 interpid *id = (interpid *)self;
2073 return PyLong_FromLongLong(id->id);
2074}
2075
2076static PyNumberMethods interpid_as_number = {
2077 0, /* nb_add */
2078 0, /* nb_subtract */
2079 0, /* nb_multiply */
2080 0, /* nb_remainder */
2081 0, /* nb_divmod */
2082 0, /* nb_power */
2083 0, /* nb_negative */
2084 0, /* nb_positive */
2085 0, /* nb_absolute */
2086 0, /* nb_bool */
2087 0, /* nb_invert */
2088 0, /* nb_lshift */
2089 0, /* nb_rshift */
2090 0, /* nb_and */
2091 0, /* nb_xor */
2092 0, /* nb_or */
2093 (unaryfunc)interpid_int, /* nb_int */
2094 0, /* nb_reserved */
2095 0, /* nb_float */
2096
2097 0, /* nb_inplace_add */
2098 0, /* nb_inplace_subtract */
2099 0, /* nb_inplace_multiply */
2100 0, /* nb_inplace_remainder */
2101 0, /* nb_inplace_power */
2102 0, /* nb_inplace_lshift */
2103 0, /* nb_inplace_rshift */
2104 0, /* nb_inplace_and */
2105 0, /* nb_inplace_xor */
2106 0, /* nb_inplace_or */
2107
2108 0, /* nb_floor_divide */
2109 0, /* nb_true_divide */
2110 0, /* nb_inplace_floor_divide */
2111 0, /* nb_inplace_true_divide */
2112
2113 (unaryfunc)interpid_int, /* nb_index */
2114};
2115
2116static Py_hash_t
2117interpid_hash(PyObject *self)
2118{
2119 interpid *id = (interpid *)self;
2120 PyObject *obj = PyLong_FromLongLong(id->id);
2121 if (obj == NULL) {
2122 return -1;
2123 }
2124 Py_hash_t hash = PyObject_Hash(obj);
2125 Py_DECREF(obj);
2126 return hash;
2127}
2128
2129static PyObject *
2130interpid_richcompare(PyObject *self, PyObject *other, int op)
2131{
2132 if (op != Py_EQ && op != Py_NE) {
2133 Py_RETURN_NOTIMPLEMENTED;
2134 }
2135
2136 if (!PyObject_TypeCheck(self, &InterpreterIDtype)) {
2137 Py_RETURN_NOTIMPLEMENTED;
2138 }
2139
2140 interpid *id = (interpid *)self;
2141 int equal;
2142 if (PyObject_TypeCheck(other, &InterpreterIDtype)) {
2143 interpid *otherid = (interpid *)other;
2144 equal = (id->id == otherid->id);
2145 }
2146 else {
2147 other = PyNumber_Long(other);
2148 if (other == NULL) {
2149 PyErr_Clear();
2150 Py_RETURN_NOTIMPLEMENTED;
2151 }
2152 int64_t otherid = PyLong_AsLongLong(other);
2153 Py_DECREF(other);
2154 if (otherid == -1 && PyErr_Occurred() != NULL) {
2155 return NULL;
2156 }
2157 if (otherid < 0) {
2158 equal = 0;
2159 }
2160 else {
2161 equal = (id->id == otherid);
2162 }
2163 }
2164
2165 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
2166 Py_RETURN_TRUE;
2167 }
2168 Py_RETURN_FALSE;
2169}
2170
2171PyDoc_STRVAR(interpid_doc,
2172"A interpreter ID identifies a interpreter and may be used as an int.");
2173
2174static PyTypeObject InterpreterIDtype = {
2175 PyVarObject_HEAD_INIT(&PyType_Type, 0)
2176 "interpreters.InterpreterID", /* tp_name */
2177 sizeof(interpid), /* tp_size */
2178 0, /* tp_itemsize */
2179 (destructor)interpid_dealloc, /* tp_dealloc */
2180 0, /* tp_print */
2181 0, /* tp_getattr */
2182 0, /* tp_setattr */
2183 0, /* tp_as_async */
2184 (reprfunc)interpid_repr, /* tp_repr */
2185 &interpid_as_number, /* tp_as_number */
2186 0, /* tp_as_sequence */
2187 0, /* tp_as_mapping */
2188 interpid_hash, /* tp_hash */
2189 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04002190 (reprfunc)interpid_str, /* tp_str */
Eric Snow4c6955e2018-02-16 18:53:40 -07002191 0, /* tp_getattro */
2192 0, /* tp_setattro */
2193 0, /* tp_as_buffer */
2194 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
2195 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
2196 interpid_doc, /* tp_doc */
2197 0, /* tp_traverse */
2198 0, /* tp_clear */
2199 interpid_richcompare, /* tp_richcompare */
2200 0, /* tp_weaklistoffset */
2201 0, /* tp_iter */
2202 0, /* tp_iternext */
2203 0, /* tp_methods */
2204 0, /* tp_members */
2205 0, /* tp_getset */
2206 0, /* tp_base */
2207 0, /* tp_dict */
2208 0, /* tp_descr_get */
2209 0, /* tp_descr_set */
2210 0, /* tp_dictoffset */
2211 0, /* tp_init */
2212 0, /* tp_alloc */
2213 interpid_new, /* tp_new */
2214};
2215
2216static PyObject *
2217_get_id(PyInterpreterState *interp)
2218{
2219 PY_INT64_T id = PyInterpreterState_GetID(interp);
2220 if (id < 0) {
2221 return NULL;
2222 }
2223 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
2224}
2225
2226static PyInterpreterState *
2227_look_up(PyObject *requested_id)
2228{
2229 int64_t id;
2230 if (PyObject_TypeCheck(requested_id, &InterpreterIDtype)) {
2231 id = ((interpid *)requested_id)->id;
2232 }
2233 else {
2234 id = PyLong_AsLongLong(requested_id);
2235 if (id == -1 && PyErr_Occurred() != NULL) {
2236 return NULL;
2237 }
2238 assert(id <= INT64_MAX);
2239 }
2240 return _PyInterpreterState_LookUpID(id);
2241}
2242
Eric Snow7f8bfc92018-01-29 18:23:44 -07002243
2244/* module level code ********************************************************/
2245
2246/* globals is the process-global state for the module. It holds all
2247 the data that we need to share between interpreters, so it cannot
2248 hold PyObject values. */
2249static struct globals {
2250 _channels channels;
2251} _globals = {{0}};
2252
2253static int
2254_init_globals(void)
2255{
2256 if (_channels_init(&_globals.channels) != 0) {
2257 return -1;
2258 }
2259 return 0;
2260}
2261
2262static _channels *
2263_global_channels(void) {
2264 return &_globals.channels;
2265}
2266
2267static PyObject *
2268interp_create(PyObject *self, PyObject *args)
2269{
2270 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
2271 return NULL;
2272 }
2273
2274 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002275 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2276 // XXX Possible GILState issues?
2277 PyThreadState *tstate = Py_NewInterpreter();
Eric Snow7f8bfc92018-01-29 18:23:44 -07002278 PyThreadState_Swap(save_tstate);
2279 if (tstate == NULL) {
2280 /* Since no new thread state was created, there is no exception to
2281 propagate; raise a fresh one after swapping in the old thread
2282 state. */
2283 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2284 return NULL;
2285 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002286 if (_PyInterpreterState_IDInitref(tstate->interp) != 0) {
2287 goto error;
2288 };
Eric Snow7f8bfc92018-01-29 18:23:44 -07002289 return _get_id(tstate->interp);
Eric Snow4c6955e2018-02-16 18:53:40 -07002290
2291error:
Eric Snowf53d9f22018-02-20 16:30:17 -07002292 // XXX Possible GILState issues?
Eric Snow4c6955e2018-02-16 18:53:40 -07002293 save_tstate = PyThreadState_Swap(tstate);
2294 Py_EndInterpreter(tstate);
2295 PyThreadState_Swap(save_tstate);
2296 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002297}
2298
2299PyDoc_STRVAR(create_doc,
2300"create() -> ID\n\
2301\n\
2302Create a new interpreter and return a unique generated ID.");
2303
2304
2305static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002306interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002307{
Eric Snow6d2cd902018-05-16 15:04:57 -04002308 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002309 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002310 // XXX Use "L" for id?
2311 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2312 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002313 return NULL;
2314 }
2315 if (!PyLong_Check(id)) {
2316 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2317 return NULL;
2318 }
2319
2320 // Look up the interpreter.
2321 PyInterpreterState *interp = _look_up(id);
2322 if (interp == NULL) {
2323 return NULL;
2324 }
2325
2326 // Ensure we don't try to destroy the current interpreter.
2327 PyInterpreterState *current = _get_current();
2328 if (current == NULL) {
2329 return NULL;
2330 }
2331 if (interp == current) {
2332 PyErr_SetString(PyExc_RuntimeError,
2333 "cannot destroy the current interpreter");
2334 return NULL;
2335 }
2336
2337 // Ensure the interpreter isn't running.
2338 /* XXX We *could* support destroying a running interpreter but
2339 aren't going to worry about it for now. */
2340 if (_ensure_not_running(interp) < 0) {
2341 return NULL;
2342 }
2343
2344 // Destroy the interpreter.
2345 //PyInterpreterState_Delete(interp);
Eric Snowf53d9f22018-02-20 16:30:17 -07002346 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2347 // XXX Possible GILState issues?
2348 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002349 Py_EndInterpreter(tstate);
2350 PyThreadState_Swap(save_tstate);
2351
2352 Py_RETURN_NONE;
2353}
2354
2355PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002356"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002357\n\
2358Destroy the identified interpreter.\n\
2359\n\
2360Attempting to destroy the current interpreter results in a RuntimeError.\n\
2361So does an unrecognized ID.");
2362
2363
2364static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302365interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002366{
2367 PyObject *ids, *id;
2368 PyInterpreterState *interp;
2369
2370 ids = PyList_New(0);
2371 if (ids == NULL) {
2372 return NULL;
2373 }
2374
2375 interp = PyInterpreterState_Head();
2376 while (interp != NULL) {
2377 id = _get_id(interp);
2378 if (id == NULL) {
2379 Py_DECREF(ids);
2380 return NULL;
2381 }
2382 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002383 int res = PyList_Insert(ids, 0, id);
2384 Py_DECREF(id);
2385 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002386 Py_DECREF(ids);
2387 return NULL;
2388 }
2389
2390 interp = PyInterpreterState_Next(interp);
2391 }
2392
2393 return ids;
2394}
2395
2396PyDoc_STRVAR(list_all_doc,
2397"list_all() -> [ID]\n\
2398\n\
2399Return a list containing the ID of every existing interpreter.");
2400
2401
2402static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302403interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002404{
2405 PyInterpreterState *interp =_get_current();
2406 if (interp == NULL) {
2407 return NULL;
2408 }
2409 return _get_id(interp);
2410}
2411
2412PyDoc_STRVAR(get_current_doc,
2413"get_current() -> ID\n\
2414\n\
2415Return the ID of current interpreter.");
2416
2417
2418static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302419interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002420{
2421 // Currently, 0 is always the main interpreter.
Eric Snow6d2cd902018-05-16 15:04:57 -04002422 PY_INT64_T id = 0;
2423 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002424}
2425
2426PyDoc_STRVAR(get_main_doc,
2427"get_main() -> ID\n\
2428\n\
2429Return the ID of main interpreter.");
2430
2431
2432static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002433interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002434{
Eric Snow6d2cd902018-05-16 15:04:57 -04002435 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002436 PyObject *id, *code;
2437 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002438 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2439 "OU|O:run_string", kwlist,
2440 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002441 return NULL;
2442 }
2443 if (!PyLong_Check(id)) {
2444 PyErr_SetString(PyExc_TypeError, "first arg (ID) must be an int");
2445 return NULL;
2446 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002447
2448 // Look up the interpreter.
2449 PyInterpreterState *interp = _look_up(id);
2450 if (interp == NULL) {
2451 return NULL;
2452 }
2453
2454 // Extract code.
2455 Py_ssize_t size;
2456 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2457 if (codestr == NULL) {
2458 return NULL;
2459 }
2460 if (strlen(codestr) != (size_t)size) {
2461 PyErr_SetString(PyExc_ValueError,
2462 "source code string cannot contain null bytes");
2463 return NULL;
2464 }
2465
2466 // Run the code in the interpreter.
2467 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2468 return NULL;
2469 }
2470 Py_RETURN_NONE;
2471}
2472
2473PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002474"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002475\n\
2476Execute the provided string in the identified interpreter.\n\
2477\n\
2478See PyRun_SimpleStrings.");
2479
2480
2481static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002482object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002483{
Eric Snow6d2cd902018-05-16 15:04:57 -04002484 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002485 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002486 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2487 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002488 return NULL;
2489 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002490
Eric Snow7f8bfc92018-01-29 18:23:44 -07002491 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2492 Py_RETURN_TRUE;
2493 }
2494 PyErr_Clear();
2495 Py_RETURN_FALSE;
2496}
2497
2498PyDoc_STRVAR(is_shareable_doc,
2499"is_shareable(obj) -> bool\n\
2500\n\
2501Return True if the object's data may be shared between interpreters and\n\
2502False otherwise.");
2503
2504
2505static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002506interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002507{
Eric Snow6d2cd902018-05-16 15:04:57 -04002508 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002509 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002510 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2511 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002512 return NULL;
2513 }
2514 if (!PyLong_Check(id)) {
2515 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2516 return NULL;
2517 }
2518
2519 PyInterpreterState *interp = _look_up(id);
2520 if (interp == NULL) {
2521 return NULL;
2522 }
2523 int is_running = _is_running(interp);
2524 if (is_running < 0) {
2525 return NULL;
2526 }
2527 if (is_running) {
2528 Py_RETURN_TRUE;
2529 }
2530 Py_RETURN_FALSE;
2531}
2532
2533PyDoc_STRVAR(is_running_doc,
2534"is_running(id) -> bool\n\
2535\n\
2536Return whether or not the identified interpreter is running.");
2537
2538static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302539channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002540{
2541 int64_t cid = _channel_create(&_globals.channels);
2542 if (cid < 0) {
2543 return NULL;
2544 }
2545 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002546 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002547 if (id == NULL) {
2548 if (_channel_destroy(&_globals.channels, cid) != 0) {
2549 // XXX issue a warning?
2550 }
2551 return NULL;
2552 }
2553 assert(((channelid *)id)->channels != NULL);
2554 return id;
2555}
2556
2557PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002558"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002559\n\
2560Create a new cross-interpreter channel and return a unique generated ID.");
2561
2562static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002563channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002564{
Eric Snow6d2cd902018-05-16 15:04:57 -04002565 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002566 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002567 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2568 "O:channel_destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002569 return NULL;
2570 }
2571 int64_t cid = _coerce_id(id);
2572 if (cid < 0) {
2573 return NULL;
2574 }
2575
2576 if (_channel_destroy(&_globals.channels, cid) != 0) {
2577 return NULL;
2578 }
2579 Py_RETURN_NONE;
2580}
2581
2582PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002583"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002584\n\
2585Close and finalize the channel. Afterward attempts to use the channel\n\
2586will behave as though it never existed.");
2587
2588static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302589channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002590{
2591 int64_t count = 0;
2592 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2593 if (cids == NULL) {
2594 if (count == 0) {
2595 return PyList_New(0);
2596 }
2597 return NULL;
2598 }
2599 PyObject *ids = PyList_New((Py_ssize_t)count);
2600 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002601 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002602 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002603 int64_t *cur = cids;
2604 for (int64_t i=0; i < count; cur++, i++) {
2605 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002606 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002607 if (id == NULL) {
2608 Py_DECREF(ids);
2609 ids = NULL;
2610 break;
2611 }
2612 PyList_SET_ITEM(ids, i, id);
2613 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002614
2615finally:
2616 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002617 return ids;
2618}
2619
2620PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002621"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002622\n\
2623Return the list of all IDs for active channels.");
2624
2625static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002626channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002627{
Eric Snow6d2cd902018-05-16 15:04:57 -04002628 static char *kwlist[] = {"cid", "obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002629 PyObject *id;
2630 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002631 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2632 "OO:channel_send", kwlist, &id, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002633 return NULL;
2634 }
2635 int64_t cid = _coerce_id(id);
2636 if (cid < 0) {
2637 return NULL;
2638 }
2639
2640 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2641 return NULL;
2642 }
2643 Py_RETURN_NONE;
2644}
2645
2646PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002647"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002648\n\
2649Add the object's data to the channel's queue.");
2650
2651static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002652channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002653{
Eric Snow6d2cd902018-05-16 15:04:57 -04002654 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002655 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002656 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2657 "O:channel_recv", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002658 return NULL;
2659 }
2660 int64_t cid = _coerce_id(id);
2661 if (cid < 0) {
2662 return NULL;
2663 }
2664
2665 return _channel_recv(&_globals.channels, cid);
2666}
2667
2668PyDoc_STRVAR(channel_recv_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002669"channel_recv(cid) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002670\n\
2671Return a new object from the data at the from of the channel's queue.");
2672
2673static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002674channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002675{
Eric Snow6d2cd902018-05-16 15:04:57 -04002676 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
2677 PyObject *id;
2678 int send = 0;
2679 int recv = 0;
2680 int force = 0;
2681 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2682 "O|$ppp:channel_close", kwlist,
2683 &id, &send, &recv, &force)) {
2684 return NULL;
2685 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002686 int64_t cid = _coerce_id(id);
2687 if (cid < 0) {
2688 return NULL;
2689 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002690
Eric Snow3ab01362018-05-17 10:27:09 -04002691 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002692 return NULL;
2693 }
2694 Py_RETURN_NONE;
2695}
2696
2697PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002698"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002699\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002700Close the channel for all interpreters.\n\
2701\n\
2702If the channel is empty then the keyword args are ignored and both\n\
2703ends are immediately closed. Otherwise, if 'force' is True then\n\
2704all queued items are released and both ends are immediately\n\
2705closed.\n\
2706\n\
2707If the channel is not empty *and* 'force' is False then following\n\
2708happens:\n\
2709\n\
2710 * recv is True (regardless of send):\n\
2711 - raise ChannelNotEmptyError\n\
2712 * recv is None and send is None:\n\
2713 - raise ChannelNotEmptyError\n\
2714 * send is True and recv is not True:\n\
2715 - fully close the 'send' end\n\
2716 - close the 'recv' end to interpreters not already receiving\n\
2717 - fully close it once empty\n\
2718\n\
2719Closing an already closed channel results in a ChannelClosedError.\n\
2720\n\
2721Once the channel's ID has no more ref counts in any interpreter\n\
2722the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002723
2724static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002725channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002726{
2727 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002728 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002729 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002730 int send = 0;
2731 int recv = 0;
2732 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002733 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04002734 "O|$ppp:channel_release", kwlist,
2735 &id, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002736 return NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002737 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002738 int64_t cid = _coerce_id(id);
2739 if (cid < 0) {
2740 return NULL;
2741 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002742 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002743 send = 1;
2744 recv = 1;
2745 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002746
2747 // XXX Handle force is True.
2748 // XXX Fix implicit release.
2749
Eric Snow7f8bfc92018-01-29 18:23:44 -07002750 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2751 return NULL;
2752 }
2753 Py_RETURN_NONE;
2754}
2755
Eric Snow6d2cd902018-05-16 15:04:57 -04002756PyDoc_STRVAR(channel_release_doc,
2757"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002758\n\
2759Close the channel for the current interpreter. 'send' and 'recv'\n\
2760(bool) may be used to indicate the ends to close. By default both\n\
2761ends are closed. Closing an already closed end is a noop.");
2762
2763static PyObject *
2764channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2765{
2766 return channelid_new(&ChannelIDtype, args, kwds);
2767}
2768
2769static PyMethodDef module_functions[] = {
2770 {"create", (PyCFunction)interp_create,
2771 METH_VARARGS, create_doc},
2772 {"destroy", (PyCFunction)interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002773 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302774 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002775 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302776 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002777 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302778 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002779 METH_NOARGS, get_main_doc},
2780 {"is_running", (PyCFunction)interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002781 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002782 {"run_string", (PyCFunction)interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002783 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002784
2785 {"is_shareable", (PyCFunction)object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002786 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002787
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302788 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002789 METH_NOARGS, channel_create_doc},
2790 {"channel_destroy", (PyCFunction)channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002791 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302792 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002793 METH_NOARGS, channel_list_all_doc},
2794 {"channel_send", (PyCFunction)channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002795 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002796 {"channel_recv", (PyCFunction)channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002797 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
2798 {"channel_close", (PyCFunction)channel_close,
2799 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
2800 {"channel_release", (PyCFunction)channel_release,
2801 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002802 {"_channel_id", (PyCFunction)channel__channel_id,
2803 METH_VARARGS | METH_KEYWORDS, NULL},
2804
2805 {NULL, NULL} /* sentinel */
2806};
2807
2808
2809/* initialization function */
2810
2811PyDoc_STRVAR(module_doc,
2812"This module provides primitive operations to manage Python interpreters.\n\
2813The 'interpreters' module provides a more convenient interface.");
2814
2815static struct PyModuleDef interpretersmodule = {
2816 PyModuleDef_HEAD_INIT,
2817 "_xxsubinterpreters", /* m_name */
2818 module_doc, /* m_doc */
2819 -1, /* m_size */
2820 module_functions, /* m_methods */
2821 NULL, /* m_slots */
2822 NULL, /* m_traverse */
2823 NULL, /* m_clear */
2824 NULL /* m_free */
2825};
2826
2827
2828PyMODINIT_FUNC
2829PyInit__xxsubinterpreters(void)
2830{
2831 if (_init_globals() != 0) {
2832 return NULL;
2833 }
2834
2835 /* Initialize types */
2836 ChannelIDtype.tp_base = &PyLong_Type;
2837 if (PyType_Ready(&ChannelIDtype) != 0) {
2838 return NULL;
2839 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002840 InterpreterIDtype.tp_base = &PyLong_Type;
2841 if (PyType_Ready(&InterpreterIDtype) != 0) {
2842 return NULL;
2843 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002844
2845 /* Create the module */
2846 PyObject *module = PyModule_Create(&interpretersmodule);
2847 if (module == NULL) {
2848 return NULL;
2849 }
2850
2851 /* Add exception types */
2852 PyObject *ns = PyModule_GetDict(module); // borrowed
2853 if (interp_exceptions_init(ns) != 0) {
2854 return NULL;
2855 }
2856 if (channel_exceptions_init(ns) != 0) {
2857 return NULL;
2858 }
2859
2860 /* Add other types */
2861 Py_INCREF(&ChannelIDtype);
2862 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2863 return NULL;
2864 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002865 Py_INCREF(&InterpreterIDtype);
2866 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&InterpreterIDtype) != 0) {
2867 return NULL;
2868 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002869
2870 if (_PyCrossInterpreterData_Register_Class(&ChannelIDtype, _channelid_shared)) {
2871 return NULL;
2872 }
2873
2874 return module;
2875}