blob: ed79a13d4a400645ce2dab90dd6f888443fd2d3d [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
10static PyInterpreterState *
11_get_current(void)
12{
13 PyThreadState *tstate = PyThreadState_Get();
14 // PyThreadState_Get() aborts if lookup fails, so we don't need
15 // to check the result for NULL.
16 return tstate->interp;
17}
18
19static int64_t
20_coerce_id(PyObject *id)
21{
22 id = PyNumber_Long(id);
23 if (id == NULL) {
24 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
25 PyErr_SetString(PyExc_TypeError,
26 "'id' must be a non-negative int");
27 }
28 else {
29 PyErr_SetString(PyExc_ValueError,
30 "'id' must be a non-negative int");
31 }
32 return -1;
33 }
34 long long cid = PyLong_AsLongLong(id);
35 if (cid == -1 && PyErr_Occurred() != NULL) {
36 PyErr_SetString(PyExc_ValueError,
37 "'id' must be a non-negative int");
38 return -1;
39 }
40 if (cid < 0) {
41 PyErr_SetString(PyExc_ValueError,
42 "'id' must be a non-negative int");
43 return -1;
44 }
45 if (cid > INT64_MAX) {
46 PyErr_SetString(PyExc_ValueError,
47 "'id' too large (must be 64-bit int)");
48 return -1;
49 }
50 return cid;
51}
52
53/* data-sharing-specific code ***********************************************/
54
55typedef struct _shareditem {
56 Py_UNICODE *name;
57 Py_ssize_t namelen;
58 _PyCrossInterpreterData data;
59} _shareditem;
60
61void
62_sharedns_clear(_shareditem *shared)
63{
64 for (_shareditem *item=shared; item->name != NULL; item += 1) {
65 _PyCrossInterpreterData_Release(&item->data);
66 }
67}
68
69static _shareditem *
70_get_shared_ns(PyObject *shareable, Py_ssize_t *lenp)
71{
72 if (shareable == NULL || shareable == Py_None) {
73 *lenp = 0;
74 return NULL;
75 }
76 Py_ssize_t len = PyDict_Size(shareable);
77 *lenp = len;
78 if (len == 0) {
79 return NULL;
80 }
81
82 _shareditem *shared = PyMem_NEW(_shareditem, len+1);
83 if (shared == NULL) {
84 return NULL;
85 }
86 for (Py_ssize_t i=0; i < len; i++) {
87 *(shared + i) = (_shareditem){0};
88 }
89 Py_ssize_t pos = 0;
90 for (Py_ssize_t i=0; i < len; i++) {
91 PyObject *key, *value;
92 if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
93 break;
94 }
95 _shareditem *item = shared + i;
96
97 if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
98 break;
99 }
100 item->name = PyUnicode_AsUnicodeAndSize(key, &item->namelen);
101 if (item->name == NULL) {
102 _PyCrossInterpreterData_Release(&item->data);
103 break;
104 }
105 (item + 1)->name = NULL; // Mark the next one as the last.
106 }
107 if (PyErr_Occurred()) {
108 _sharedns_clear(shared);
109 PyMem_Free(shared);
110 return NULL;
111 }
112 return shared;
113}
114
115static int
116_shareditem_apply(_shareditem *item, PyObject *ns)
117{
118 PyObject *name = PyUnicode_FromUnicode(item->name, item->namelen);
119 if (name == NULL) {
120 return 1;
121 }
122 PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
123 if (value == NULL) {
124 Py_DECREF(name);
125 return 1;
126 }
127 int res = PyDict_SetItem(ns, name, value);
128 Py_DECREF(name);
129 Py_DECREF(value);
130 return res;
131}
132
133// Ultimately we'd like to preserve enough information about the
134// exception and traceback that we could re-constitute (or at least
135// simulate, a la traceback.TracebackException), and even chain, a copy
136// of the exception in the calling interpreter.
137
138typedef struct _sharedexception {
139 char *msg;
140} _sharedexception;
141
142static _sharedexception *
143_get_shared_exception(void)
144{
145 _sharedexception *err = PyMem_NEW(_sharedexception, 1);
146 if (err == NULL) {
147 return NULL;
148 }
149 PyObject *exc;
150 PyObject *value;
151 PyObject *tb;
152 PyErr_Fetch(&exc, &value, &tb);
153 PyObject *msg;
154 if (value == NULL) {
155 msg = PyUnicode_FromFormat("%S", exc);
156 }
157 else {
158 msg = PyUnicode_FromFormat("%S: %S", exc, value);
159 }
160 if (msg == NULL) {
161 err->msg = "unable to format exception";
162 return err;
163 }
164 err->msg = (char *)PyUnicode_AsUTF8(msg);
165 if (err->msg == NULL) {
166 err->msg = "unable to encode exception";
167 }
168 return err;
169}
170
171static PyObject * RunFailedError;
172
173static int
174interp_exceptions_init(PyObject *ns)
175{
176 // XXX Move the exceptions into per-module memory?
177
178 // An uncaught exception came out of interp_run_string().
179 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
180 PyExc_RuntimeError, NULL);
181 if (RunFailedError == NULL) {
182 return -1;
183 }
184 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
185 return -1;
186 }
187
188 return 0;
189}
190
191static void
192_apply_shared_exception(_sharedexception *exc)
193{
194 PyErr_SetString(RunFailedError, exc->msg);
195}
196
197/* channel-specific code */
198
199static PyObject *ChannelError;
200static PyObject *ChannelNotFoundError;
201static PyObject *ChannelClosedError;
202static PyObject *ChannelEmptyError;
203
204static int
205channel_exceptions_init(PyObject *ns)
206{
207 // XXX Move the exceptions into per-module memory?
208
209 // A channel-related operation failed.
210 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
211 PyExc_RuntimeError, NULL);
212 if (ChannelError == NULL) {
213 return -1;
214 }
215 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
216 return -1;
217 }
218
219 // An operation tried to use a channel that doesn't exist.
220 ChannelNotFoundError = PyErr_NewException(
221 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
222 if (ChannelNotFoundError == NULL) {
223 return -1;
224 }
225 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
226 return -1;
227 }
228
229 // An operation tried to use a closed channel.
230 ChannelClosedError = PyErr_NewException(
231 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
232 if (ChannelClosedError == NULL) {
233 return -1;
234 }
235 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
236 return -1;
237 }
238
239 // An operation tried to pop from an empty channel.
240 ChannelEmptyError = PyErr_NewException(
241 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
242 if (ChannelEmptyError == NULL) {
243 return -1;
244 }
245 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
246 return -1;
247 }
248
249 return 0;
250}
251
252struct _channelend;
253
254typedef struct _channelend {
255 struct _channelend *next;
256 int64_t interp;
257 int open;
258} _channelend;
259
260static _channelend *
261_channelend_new(int64_t interp)
262{
263 _channelend *end = PyMem_NEW(_channelend, 1);
264 if (end == NULL) {
265 return NULL;
266 }
267
268 end->next = NULL;
269 end->interp = interp;
270
271 end->open = 1;
272
273 return end;
274}
275
276static void
277_channelend_free_all(_channelend *end) {
278 while (end != NULL) {
279 _channelend *last = end;
280 end = end->next;
281 PyMem_Free(last);
282 }
283}
284
285static _channelend *
286_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
287{
288 _channelend *prev = NULL;
289 _channelend *end = first;
290 while (end != NULL) {
291 if (end->interp == interp) {
292 break;
293 }
294 prev = end;
295 end = end->next;
296 }
297 if (pprev != NULL) {
298 *pprev = prev;
299 }
300 return end;
301}
302
303struct _channelitem;
304
305typedef struct _channelitem {
306 _PyCrossInterpreterData *data;
307 struct _channelitem *next;
308} _channelitem;
309
310struct _channel;
311
312typedef struct _channel {
313 PyThread_type_lock mutex;
314
315 int open;
316
317 int64_t count;
318 _channelitem *first;
319 _channelitem *last;
320
321 // Note that the list entries are never removed for interpreter
322 // for which the channel is closed. This should be a problem in
323 // practice. Also, a channel isn't automatically closed when an
324 // interpreter is destroyed.
325 int64_t numsendopen;
326 int64_t numrecvopen;
327 _channelend *send;
328 _channelend *recv;
329} _PyChannelState;
330
331static _PyChannelState *
332_channel_new(void)
333{
334 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
335 if (chan == NULL) {
336 return NULL;
337 }
338 chan->mutex = PyThread_allocate_lock();
339 if (chan->mutex == NULL) {
340 PyMem_Free(chan);
341 PyErr_SetString(ChannelError,
342 "can't initialize mutex for new channel");
343 return NULL;
344 }
345
346 chan->open = 1;
347
348 chan->count = 0;
349 chan->first = NULL;
350 chan->last = NULL;
351
352 chan->numsendopen = 0;
353 chan->numrecvopen = 0;
354 chan->send = NULL;
355 chan->recv = NULL;
356
357 return chan;
358}
359
360static _channelend *
361_channel_add_end(_PyChannelState *chan, _channelend *prev, int64_t interp,
362 int send)
363{
364 _channelend *end = _channelend_new(interp);
365 if (end == NULL) {
366 return NULL;
367 }
368
369 if (prev == NULL) {
370 if (send) {
371 chan->send = end;
372 }
373 else {
374 chan->recv = end;
375 }
376 }
377 else {
378 prev->next = end;
379 }
380 if (send) {
381 chan->numsendopen += 1;
382 }
383 else {
384 chan->numrecvopen += 1;
385 }
386 return end;
387}
388
389static _channelend *
390_channel_associate_end(_PyChannelState *chan, int64_t interp, int send)
391{
392 if (!chan->open) {
393 PyErr_SetString(ChannelClosedError, "channel closed");
394 return NULL;
395 }
396
397 _channelend *prev;
398 _channelend *end = _channelend_find(send ? chan->send : chan->recv,
399 interp, &prev);
400 if (end != NULL) {
401 if (!end->open) {
402 PyErr_SetString(ChannelClosedError, "channel already closed");
403 return NULL;
404 }
405 // already associated
406 return end;
407 }
408 return _channel_add_end(chan, prev, interp, send);
409}
410
411static void
412_channel_close_channelend(_PyChannelState *chan, _channelend *end, int send)
413{
414 end->open = 0;
415 if (send) {
416 chan->numsendopen -= 1;
417 }
418 else {
419 chan->numrecvopen -= 1;
420 }
421}
422
423static int
424_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int which)
425{
426 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
427
428 int res = -1;
429 if (!chan->open) {
430 PyErr_SetString(ChannelClosedError, "channel already closed");
431 goto done;
432 }
433
434 _channelend *prev;
435 _channelend *end;
436 if (which >= 0) { // send/both
437 end = _channelend_find(chan->send, interp, &prev);
438 if (end == NULL) {
439 // never associated so add it
440 end = _channel_add_end(chan, prev, interp, 1);
441 if (end == NULL) {
442 goto done;
443 }
444 }
445 _channel_close_channelend(chan, end, 1);
446 }
447 if (which <= 0) { // recv/both
448 end = _channelend_find(chan->recv, interp, &prev);
449 if (end == NULL) {
450 // never associated so add it
451 end = _channel_add_end(chan, prev, interp, 0);
452 if (end == NULL) {
453 goto done;
454 }
455 }
456 _channel_close_channelend(chan, end, 0);
457 }
458
459 if (chan->numsendopen == 0 && chan->numrecvopen == 0) {
460 if (chan->send != NULL || chan->recv != NULL) {
461 chan->open = 0;
462 }
463 }
464
465 res = 0;
466done:
467 PyThread_release_lock(chan->mutex);
468 return res;
469}
470
471static int
472_channel_close_all(_PyChannelState *chan)
473{
474 int res = -1;
475 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
476
477 if (!chan->open) {
478 PyErr_SetString(ChannelClosedError, "channel already closed");
479 goto done;
480 }
481
482 chan->open = 0;
483
484 // We *could* also just leave these in place, since we've marked
485 // the channel as closed already.
486
487 // Ensure all the "send"-associated interpreters are closed.
488 _channelend *end;
489 for (end = chan->send; end != NULL; end = end->next) {
490 _channel_close_channelend(chan, end, 1);
491 }
492
493 // Ensure all the "recv"-associated interpreters are closed.
494 for (end = chan->recv; end != NULL; end = end->next) {
495 _channel_close_channelend(chan, end, 0);
496 }
497
498 res = 0;
499done:
500 PyThread_release_lock(chan->mutex);
501 return res;
502}
503
504static int
505_channel_add(_PyChannelState *chan, int64_t interp,
506 _PyCrossInterpreterData *data)
507{
508 int res = -1;
509
510 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
511 if (_channel_associate_end(chan, interp, 1) == NULL) {
512 goto done;
513 }
514
515 _channelitem *item = PyMem_NEW(_channelitem, 1);
516 if (item == NULL) {
517 goto done;
518 }
519 item->data = data;
520 item->next = NULL;
521
522 chan->count += 1;
523 if (chan->first == NULL) {
524 chan->first = item;
525 }
526 chan->last = item;
527
528 res = 0;
529done:
530 PyThread_release_lock(chan->mutex);
531 return res;
532}
533
534static _PyCrossInterpreterData *
535_channel_next(_PyChannelState *chan, int64_t interp)
536{
537 _PyCrossInterpreterData *data = NULL;
538 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
539 if (_channel_associate_end(chan, interp, 0) == NULL) {
540 goto done;
541 }
542
543 _channelitem *item = chan->first;
544 if (item == NULL) {
545 goto done;
546 }
547 chan->first = item->next;
548 if (chan->last == item) {
549 chan->last = NULL;
550 }
551 chan->count -= 1;
552
553 data = item->data;
554 PyMem_Free(item);
555
556done:
557 PyThread_release_lock(chan->mutex);
558 return data;
559}
560
561static void
562_channel_clear(_PyChannelState *chan)
563{
564 _channelitem *item = chan->first;
565 while (item != NULL) {
566 _PyCrossInterpreterData_Release(item->data);
567 PyMem_Free(item->data);
568 _channelitem *last = item;
569 item = item->next;
570 PyMem_Free(last);
571 }
572 chan->first = NULL;
573 chan->last = NULL;
574}
575
576static void
577_channel_free(_PyChannelState *chan)
578{
579 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
580 _channel_clear(chan);
581 _channelend_free_all(chan->send);
582 _channelend_free_all(chan->recv);
583 PyThread_release_lock(chan->mutex);
584
585 PyThread_free_lock(chan->mutex);
586 PyMem_Free(chan);
587}
588
589struct _channelref;
590
591typedef struct _channelref {
592 int64_t id;
593 _PyChannelState *chan;
594 struct _channelref *next;
595 Py_ssize_t objcount;
596} _channelref;
597
598static _channelref *
599_channelref_new(int64_t id, _PyChannelState *chan)
600{
601 _channelref *ref = PyMem_NEW(_channelref, 1);
602 if (ref == NULL) {
603 return NULL;
604 }
605 ref->id = id;
606 ref->chan = chan;
607 ref->next = NULL;
608 ref->objcount = 0;
609 return ref;
610}
611
612static _channelref *
613_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
614{
615 _channelref *prev = NULL;
616 _channelref *ref = first;
617 while (ref != NULL) {
618 if (ref->id == id) {
619 break;
620 }
621 prev = ref;
622 ref = ref->next;
623 }
624 if (pprev != NULL) {
625 *pprev = prev;
626 }
627 return ref;
628}
629
630typedef struct _channels {
631 PyThread_type_lock mutex;
632 _channelref *head;
633 int64_t numopen;
634 int64_t next_id;
635} _channels;
636
637static int
638_channels_init(_channels *channels)
639{
640 if (channels->mutex == NULL) {
641 channels->mutex = PyThread_allocate_lock();
642 if (channels->mutex == NULL) {
643 PyMem_Free(channels);
644 PyErr_SetString(ChannelError,
645 "can't initialize mutex for channel management");
646 return -1;
647 }
648 }
649 channels->head = NULL;
650 channels->numopen = 0;
651 channels->next_id = 0;
652 return 0;
653}
654
655static int64_t
656_channels_next_id(_channels *channels) // needs lock
657{
658 int64_t id = channels->next_id;
659 if (id < 0) {
660 /* overflow */
661 PyErr_SetString(ChannelError,
662 "failed to get a channel ID");
663 return -1;
664 }
665 channels->next_id += 1;
666 return id;
667}
668
669static _PyChannelState *
670_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
671{
672 _PyChannelState *chan = NULL;
673 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
674 if (pmutex != NULL) {
675 *pmutex = NULL;
676 }
677
678 _channelref *ref = _channelref_find(channels->head, id, NULL);
679 if (ref == NULL) {
680 PyErr_Format(ChannelNotFoundError, "channel %d not found", id);
681 goto done;
682 }
683 if (ref->chan == NULL || !ref->chan->open) {
684 PyErr_Format(ChannelClosedError, "channel %d closed", id);
685 goto done;
686 }
687
688 if (pmutex != NULL) {
689 // The mutex will be closed by the caller.
690 *pmutex = channels->mutex;
691 }
692
693 chan = ref->chan;
694done:
695 if (pmutex == NULL || *pmutex == NULL) {
696 PyThread_release_lock(channels->mutex);
697 }
698 return chan;
699}
700
701static int64_t
702_channels_add(_channels *channels, _PyChannelState *chan)
703{
704 int64_t cid = -1;
705 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
706
707 // Create a new ref.
708 int64_t id = _channels_next_id(channels);
709 if (id < 0) {
710 goto done;
711 }
712 _channelref *ref = _channelref_new(id, chan);
713 if (ref == NULL) {
714 goto done;
715 }
716
717 // Add it to the list.
718 // We assume that the channel is a new one (not already in the list).
719 ref->next = channels->head;
720 channels->head = ref;
721 channels->numopen += 1;
722
723 cid = id;
724done:
725 PyThread_release_lock(channels->mutex);
726 return cid;
727}
728
729static int
730_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan)
731{
732 int res = -1;
733 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
734 if (pchan != NULL) {
735 *pchan = NULL;
736 }
737
738 _channelref *ref = _channelref_find(channels->head, cid, NULL);
739 if (ref == NULL) {
740 PyErr_Format(ChannelNotFoundError, "channel %d not found", cid);
741 goto done;
742 }
743
744 if (ref->chan == NULL) {
745 PyErr_Format(ChannelClosedError, "channel %d closed", cid);
746 goto done;
747 }
748 else {
749 if (_channel_close_all(ref->chan) != 0) {
750 goto done;
751 }
752 if (pchan != NULL) {
753 *pchan = ref->chan;
754 }
755 ref->chan = NULL;
756 }
757
758 res = 0;
759done:
760 PyThread_release_lock(channels->mutex);
761 return res;
762}
763
764static void
765_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
766 _PyChannelState **pchan)
767{
768 if (ref == channels->head) {
769 channels->head = ref->next;
770 }
771 else {
772 prev->next = ref->next;
773 }
774 channels->numopen -= 1;
775
776 if (pchan != NULL) {
777 *pchan = ref->chan;
778 }
779 PyMem_Free(ref);
780}
781
782static int
783_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
784{
785 int res = -1;
786 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
787
788 if (pchan != NULL) {
789 *pchan = NULL;
790 }
791
792 _channelref *prev = NULL;
793 _channelref *ref = _channelref_find(channels->head, id, &prev);
794 if (ref == NULL) {
795 PyErr_Format(ChannelNotFoundError, "channel %d not found", id);
796 goto done;
797 }
798
799 _channels_remove_ref(channels, ref, prev, pchan);
800
801 res = 0;
802done:
803 PyThread_release_lock(channels->mutex);
804 return res;
805}
806
807static int
808_channels_add_id_object(_channels *channels, int64_t id)
809{
810 int res = -1;
811 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
812
813 _channelref *ref = _channelref_find(channels->head, id, NULL);
814 if (ref == NULL) {
815 PyErr_Format(ChannelNotFoundError, "channel %d not found", id);
816 goto done;
817 }
818 ref->objcount += 1;
819
820 res = 0;
821done:
822 PyThread_release_lock(channels->mutex);
823 return res;
824}
825
826static void
827_channels_drop_id_object(_channels *channels, int64_t id)
828{
829 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
830
831 _channelref *prev = NULL;
832 _channelref *ref = _channelref_find(channels->head, id, &prev);
833 if (ref == NULL) {
834 // Already destroyed.
835 goto done;
836 }
837 ref->objcount -= 1;
838
839 // Destroy if no longer used.
840 if (ref->objcount == 0) {
841 _PyChannelState *chan = NULL;
842 _channels_remove_ref(channels, ref, prev, &chan);
843 if (chan != NULL) {
844 _channel_free(chan);
845 }
846 }
847
848done:
849 PyThread_release_lock(channels->mutex);
850}
851
852int64_t *
853_channels_list_all(_channels *channels, int64_t *count)
854{
855 int64_t *cids = NULL;
856 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
857 int64_t numopen = channels->numopen;
858 if (numopen >= PY_SSIZE_T_MAX) {
859 PyErr_SetString(PyExc_RuntimeError, "too many channels open");
860 goto done;
861 }
862 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
863 if (ids == NULL) {
864 goto done;
865 }
866 _channelref *ref = channels->head;
867 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
868 ids[i] = ref->id;
869 }
870 *count = channels->numopen;
871
872 cids = ids;
873done:
874 PyThread_release_lock(channels->mutex);
875 return cids;
876}
877
878/* "high"-level channel-related functions */
879
880static int64_t
881_channel_create(_channels *channels)
882{
883 _PyChannelState *chan = _channel_new();
884 if (chan == NULL) {
885 return -1;
886 }
887 int64_t id = _channels_add(channels, chan);
888 if (id < 0) {
889 _channel_free(chan);
890 return -1;
891 }
892 return id;
893}
894
895static int
896_channel_destroy(_channels *channels, int64_t id)
897{
898 _PyChannelState *chan = NULL;
899 if (_channels_remove(channels, id, &chan) != 0) {
900 return -1;
901 }
902 if (chan != NULL) {
903 _channel_free(chan);
904 }
905 return 0;
906}
907
908static int
909_channel_send(_channels *channels, int64_t id, PyObject *obj)
910{
911 PyInterpreterState *interp = _get_current();
912 if (interp == NULL) {
913 return -1;
914 }
915
916 // Look up the channel.
917 PyThread_type_lock mutex = NULL;
918 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
919 if (chan == NULL) {
920 return -1;
921 }
922 // Past this point we are responsible for releasing the mutex.
923
924 // Convert the object to cross-interpreter data.
925 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
926 if (data == NULL) {
927 PyThread_release_lock(mutex);
928 return -1;
929 }
930 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
931 PyThread_release_lock(mutex);
932 return -1;
933 }
934
935 // Add the data to the channel.
936 int res = _channel_add(chan, interp->id, data);
937 PyThread_release_lock(mutex);
938 if (res != 0) {
939 _PyCrossInterpreterData_Release(data);
940 PyMem_Free(data);
941 return -1;
942 }
943
944 return 0;
945}
946
947static PyObject *
948_channel_recv(_channels *channels, int64_t id)
949{
950 PyInterpreterState *interp = _get_current();
951 if (interp == NULL) {
952 return NULL;
953 }
954
955 // Look up the channel.
956 PyThread_type_lock mutex = NULL;
957 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
958 if (chan == NULL) {
959 return NULL;
960 }
961 // Past this point we are responsible for releasing the mutex.
962
963 // Pop off the next item from the channel.
964 _PyCrossInterpreterData *data = _channel_next(chan, interp->id);
965 PyThread_release_lock(mutex);
966 if (data == NULL) {
967 PyErr_Format(ChannelEmptyError, "channel %d is empty", id);
968 return NULL;
969 }
970
971 // Convert the data back to an object.
972 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
973 if (obj == NULL) {
974 return NULL;
975 }
976 _PyCrossInterpreterData_Release(data);
977
978 return obj;
979}
980
981static int
982_channel_drop(_channels *channels, int64_t id, int send, int recv)
983{
984 PyInterpreterState *interp = _get_current();
985 if (interp == NULL) {
986 return -1;
987 }
988
989 // Look up the channel.
990 PyThread_type_lock mutex = NULL;
991 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
992 if (chan == NULL) {
993 return -1;
994 }
995 // Past this point we are responsible for releasing the mutex.
996
997 // Close one or both of the two ends.
998 int res =_channel_close_interpreter(chan, interp->id, send-recv);
999 PyThread_release_lock(mutex);
1000 return res;
1001}
1002
1003static int
1004_channel_close(_channels *channels, int64_t id)
1005{
1006 return _channels_close(channels, id, NULL);
1007}
1008
1009/* ChannelID class */
1010
1011#define CHANNEL_SEND 1
1012#define CHANNEL_RECV -1
1013
1014static PyTypeObject ChannelIDtype;
1015
1016typedef struct channelid {
1017 PyObject_HEAD
1018 int64_t id;
1019 int end;
1020 _channels *channels;
1021} channelid;
1022
1023static channelid *
1024newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
1025 int force)
1026{
1027 channelid *self = PyObject_New(channelid, cls);
1028 if (self == NULL) {
1029 return NULL;
1030 }
1031 self->id = cid;
1032 self->end = end;
1033 self->channels = channels;
1034
1035 if (_channels_add_id_object(channels, cid) != 0) {
1036 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1037 PyErr_Clear();
1038 }
1039 else {
1040 Py_DECREF((PyObject *)self);
1041 return NULL;
1042 }
1043 }
1044
1045 return self;
1046}
1047
1048static _channels * _global_channels(void);
1049
1050static PyObject *
1051channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1052{
1053 static char *kwlist[] = {"id", "send", "recv", "force", NULL};
1054 PyObject *id;
1055 int send = -1;
1056 int recv = -1;
1057 int force = 0;
1058 if (!PyArg_ParseTupleAndKeywords(args, kwds,
1059 "O|$ppp:ChannelID.__init__", kwlist,
1060 &id, &send, &recv, &force))
1061 return NULL;
1062
1063 // Coerce and check the ID.
1064 int64_t cid;
1065 if (PyObject_TypeCheck(id, &ChannelIDtype)) {
1066 cid = ((channelid *)id)->id;
1067 }
1068 else {
1069 cid = _coerce_id(id);
1070 if (cid < 0) {
1071 return NULL;
1072 }
1073 }
1074
1075 // Handle "send" and "recv".
1076 if (send == 0 && recv == 0) {
1077 PyErr_SetString(PyExc_ValueError,
1078 "'send' and 'recv' cannot both be False");
1079 return NULL;
1080 }
1081 int end = 0;
1082 if (send == 1) {
1083 if (recv == 0 || recv == -1) {
1084 end = CHANNEL_SEND;
1085 }
1086 }
1087 else if (recv == 1) {
1088 end = CHANNEL_RECV;
1089 }
1090
1091 return (PyObject *)newchannelid(cls, cid, end, _global_channels(), force);
1092}
1093
1094static void
1095channelid_dealloc(PyObject *v)
1096{
1097 int64_t cid = ((channelid *)v)->id;
1098 _channels *channels = ((channelid *)v)->channels;
1099 Py_TYPE(v)->tp_free(v);
1100
1101 _channels_drop_id_object(channels, cid);
1102}
1103
1104static PyObject *
1105channelid_repr(PyObject *self)
1106{
1107 PyTypeObject *type = Py_TYPE(self);
1108 const char *name = _PyType_Name(type);
1109
1110 channelid *cid = (channelid *)self;
1111 const char *fmt;
1112 if (cid->end == CHANNEL_SEND) {
1113 fmt = "%s(%d, send=True)";
1114 }
1115 else if (cid->end == CHANNEL_RECV) {
1116 fmt = "%s(%d, recv=True)";
1117 }
1118 else {
1119 fmt = "%s(%d)";
1120 }
1121 return PyUnicode_FromFormat(fmt, name, cid->id);
1122}
1123
1124PyObject *
1125channelid_int(PyObject *self)
1126{
1127 channelid *cid = (channelid *)self;
1128 return PyLong_FromLongLong(cid->id);
1129}
1130
1131static PyNumberMethods channelid_as_number = {
1132 0, /* nb_add */
1133 0, /* nb_subtract */
1134 0, /* nb_multiply */
1135 0, /* nb_remainder */
1136 0, /* nb_divmod */
1137 0, /* nb_power */
1138 0, /* nb_negative */
1139 0, /* nb_positive */
1140 0, /* nb_absolute */
1141 0, /* nb_bool */
1142 0, /* nb_invert */
1143 0, /* nb_lshift */
1144 0, /* nb_rshift */
1145 0, /* nb_and */
1146 0, /* nb_xor */
1147 0, /* nb_or */
1148 (unaryfunc)channelid_int, /* nb_int */
1149 0, /* nb_reserved */
1150 0, /* nb_float */
1151
1152 0, /* nb_inplace_add */
1153 0, /* nb_inplace_subtract */
1154 0, /* nb_inplace_multiply */
1155 0, /* nb_inplace_remainder */
1156 0, /* nb_inplace_power */
1157 0, /* nb_inplace_lshift */
1158 0, /* nb_inplace_rshift */
1159 0, /* nb_inplace_and */
1160 0, /* nb_inplace_xor */
1161 0, /* nb_inplace_or */
1162
1163 0, /* nb_floor_divide */
1164 0, /* nb_true_divide */
1165 0, /* nb_inplace_floor_divide */
1166 0, /* nb_inplace_true_divide */
1167
1168 (unaryfunc)channelid_int, /* nb_index */
1169};
1170
1171static Py_hash_t
1172channelid_hash(PyObject *self)
1173{
1174 channelid *cid = (channelid *)self;
1175 PyObject *id = PyLong_FromLongLong(cid->id);
1176 if (id == NULL) {
1177 return -1;
1178 }
1179 return PyObject_Hash(id);
1180}
1181
1182static PyObject *
1183channelid_richcompare(PyObject *self, PyObject *other, int op)
1184{
1185 if (op != Py_EQ && op != Py_NE) {
1186 Py_RETURN_NOTIMPLEMENTED;
1187 }
1188
1189 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1190 Py_RETURN_NOTIMPLEMENTED;
1191 }
1192
1193 channelid *cid = (channelid *)self;
1194 int equal;
1195 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1196 channelid *othercid = (channelid *)other;
1197 if (cid->end != othercid->end) {
1198 equal = 0;
1199 }
1200 else {
1201 equal = (cid->id == othercid->id);
1202 }
1203 }
1204 else {
1205 other = PyNumber_Long(other);
1206 if (other == NULL) {
1207 PyErr_Clear();
1208 Py_RETURN_NOTIMPLEMENTED;
1209 }
1210 int64_t othercid = PyLong_AsLongLong(other);
1211 // XXX decref other here?
1212 if (othercid == -1 && PyErr_Occurred() != NULL) {
1213 return NULL;
1214 }
1215 if (othercid < 0 || othercid > INT64_MAX) {
1216 equal = 0;
1217 }
1218 else {
1219 equal = (cid->id == othercid);
1220 }
1221 }
1222
1223 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1224 Py_RETURN_TRUE;
1225 }
1226 Py_RETURN_FALSE;
1227}
1228
1229struct _channelid_xid {
1230 int64_t id;
1231 int end;
1232};
1233
1234static PyObject *
1235_channelid_from_xid(_PyCrossInterpreterData *data)
1236{
1237 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
1238 return (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1239 _global_channels(), 0);
1240}
1241
1242static int
1243_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1244{
1245 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1246 if (xid == NULL) {
1247 return -1;
1248 }
1249 xid->id = ((channelid *)obj)->id;
1250 xid->end = ((channelid *)obj)->end;
1251
1252 data->data = xid;
1253 data->obj = obj;
1254 data->new_object = _channelid_from_xid;
1255 data->free = PyMem_Free;
1256 return 0;
1257}
1258
1259static PyObject *
1260channelid_end(PyObject *self, void *end)
1261{
1262 int force = 1;
1263 channelid *cid = (channelid *)self;
1264 if (end != NULL) {
1265 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
1266 cid->channels, force);
1267 }
1268
1269 if (cid->end == CHANNEL_SEND) {
1270 return PyUnicode_InternFromString("send");
1271 }
1272 if (cid->end == CHANNEL_RECV) {
1273 return PyUnicode_InternFromString("recv");
1274 }
1275 return PyUnicode_InternFromString("both");
1276}
1277
1278static int _channelid_end_send = CHANNEL_SEND;
1279static int _channelid_end_recv = CHANNEL_RECV;
1280
1281static PyGetSetDef channelid_getsets[] = {
1282 {"end", (getter)channelid_end, NULL,
1283 PyDoc_STR("'send', 'recv', or 'both'")},
1284 {"send", (getter)channelid_end, NULL,
1285 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1286 {"recv", (getter)channelid_end, NULL,
1287 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1288 {NULL}
1289};
1290
1291PyDoc_STRVAR(channelid_doc,
1292"A channel ID identifies a channel and may be used as an int.");
1293
1294static PyTypeObject ChannelIDtype = {
1295 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1296 "_xxsubinterpreters.ChannelID", /* tp_name */
1297 sizeof(channelid), /* tp_size */
1298 0, /* tp_itemsize */
1299 (destructor)channelid_dealloc, /* tp_dealloc */
1300 0, /* tp_print */
1301 0, /* tp_getattr */
1302 0, /* tp_setattr */
1303 0, /* tp_as_async */
1304 (reprfunc)channelid_repr, /* tp_repr */
1305 &channelid_as_number, /* tp_as_number */
1306 0, /* tp_as_sequence */
1307 0, /* tp_as_mapping */
1308 channelid_hash, /* tp_hash */
1309 0, /* tp_call */
1310 0, /* tp_str */
1311 0, /* tp_getattro */
1312 0, /* tp_setattro */
1313 0, /* tp_as_buffer */
1314 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1315 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
1316 channelid_doc, /* tp_doc */
1317 0, /* tp_traverse */
1318 0, /* tp_clear */
1319 channelid_richcompare, /* tp_richcompare */
1320 0, /* tp_weaklistoffset */
1321 0, /* tp_iter */
1322 0, /* tp_iternext */
1323 0, /* tp_methods */
1324 0, /* tp_members */
1325 channelid_getsets, /* tp_getset */
1326 0, /* tp_base */
1327 0, /* tp_dict */
1328 0, /* tp_descr_get */
1329 0, /* tp_descr_set */
1330 0, /* tp_dictoffset */
1331 0, /* tp_init */
1332 0, /* tp_alloc */
1333 // Note that we do not set tp_new to channelid_new. Instead we
1334 // set it to NULL, meaning it cannot be instantiated from Python
1335 // code. We do this because there is a strong relationship between
1336 // channel IDs and the channel lifecycle, so this limitation avoids
1337 // related complications.
1338 NULL, /* tp_new */
1339};
1340
1341/* interpreter-specific functions *******************************************/
1342
1343static PyInterpreterState *
1344_look_up(PyObject *requested_id)
1345{
1346 long long id = PyLong_AsLongLong(requested_id);
1347 if (id == -1 && PyErr_Occurred() != NULL) {
1348 return NULL;
1349 }
1350 assert(id <= INT64_MAX);
1351 return _PyInterpreterState_LookUpID(id);
1352}
1353
1354static PyObject *
1355_get_id(PyInterpreterState *interp)
1356{
1357 PY_INT64_T id = PyInterpreterState_GetID(interp);
1358 if (id < 0) {
1359 return NULL;
1360 }
1361 return PyLong_FromLongLong(id);
1362}
1363
1364static int
1365_is_running(PyInterpreterState *interp)
1366{
1367 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1368 if (PyThreadState_Next(tstate) != NULL) {
1369 PyErr_SetString(PyExc_RuntimeError,
1370 "interpreter has more than one thread");
1371 return -1;
1372 }
1373 PyFrameObject *frame = tstate->frame;
1374 if (frame == NULL) {
1375 if (PyErr_Occurred() != NULL) {
1376 return -1;
1377 }
1378 return 0;
1379 }
1380 return (int)(frame->f_executing);
1381}
1382
1383static int
1384_ensure_not_running(PyInterpreterState *interp)
1385{
1386 int is_running = _is_running(interp);
1387 if (is_running < 0) {
1388 return -1;
1389 }
1390 if (is_running) {
1391 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1392 return -1;
1393 }
1394 return 0;
1395}
1396
1397static int
1398_run_script(PyInterpreterState *interp, const char *codestr,
1399 _shareditem *shared, Py_ssize_t num_shared,
1400 _sharedexception **exc)
1401{
1402 assert(num_shared >= 0);
1403 PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
1404 if (main_mod == NULL) {
1405 goto error;
1406 }
1407 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1408 Py_DECREF(main_mod);
1409 if (ns == NULL) {
1410 goto error;
1411 }
1412 Py_INCREF(ns);
1413
1414 // Apply the cross-interpreter data.
1415 if (shared != NULL) {
1416 for (Py_ssize_t i=0; i < num_shared; i++) {
1417 _shareditem *item = &shared[i];
1418 if (_shareditem_apply(item, ns) != 0) {
1419 Py_DECREF(ns);
1420 goto error;
1421 }
1422 }
1423 }
1424
1425 // Run the string (see PyRun_SimpleStringFlags).
1426 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1427 Py_DECREF(ns);
1428 if (result == NULL) {
1429 goto error;
1430 }
1431 else {
1432 Py_DECREF(result); // We throw away the result.
1433 }
1434
1435 return 0;
1436
1437error:
1438 *exc = _get_shared_exception();
1439 PyErr_Clear();
1440 return -1;
1441}
1442
1443static int
1444_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1445 PyObject *shareables)
1446{
1447 if (_ensure_not_running(interp) < 0) {
1448 return -1;
1449 }
1450
1451 Py_ssize_t num_shared = -1;
1452 _shareditem *shared = _get_shared_ns(shareables, &num_shared);
1453 if (shared == NULL && PyErr_Occurred()) {
1454 return -1;
1455 }
1456
1457 // Switch to interpreter.
1458 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1459 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
1460
1461 // Run the script.
1462 _sharedexception *exc = NULL;
1463 int result = _run_script(interp, codestr, shared, num_shared, &exc);
1464
1465 // Switch back.
1466 if (save_tstate != NULL) {
1467 PyThreadState_Swap(save_tstate);
1468 }
1469
1470 // Propagate any exception out to the caller.
1471 if (exc != NULL) {
1472 _apply_shared_exception(exc);
1473 PyMem_Free(exc);
1474 }
1475 else if (result != 0) {
1476 // We were unable to allocate a shared exception.
1477 PyErr_NoMemory();
1478 }
1479
1480 if (shared != NULL) {
1481 _sharedns_clear(shared);
1482 PyMem_Free(shared);
1483 }
1484
1485 return result;
1486}
1487
1488
1489/* module level code ********************************************************/
1490
1491/* globals is the process-global state for the module. It holds all
1492 the data that we need to share between interpreters, so it cannot
1493 hold PyObject values. */
1494static struct globals {
1495 _channels channels;
1496} _globals = {{0}};
1497
1498static int
1499_init_globals(void)
1500{
1501 if (_channels_init(&_globals.channels) != 0) {
1502 return -1;
1503 }
1504 return 0;
1505}
1506
1507static _channels *
1508_global_channels(void) {
1509 return &_globals.channels;
1510}
1511
1512static PyObject *
1513interp_create(PyObject *self, PyObject *args)
1514{
1515 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
1516 return NULL;
1517 }
1518
1519 // Create and initialize the new interpreter.
1520 PyThreadState *tstate, *save_tstate;
1521 save_tstate = PyThreadState_Swap(NULL);
1522 tstate = Py_NewInterpreter();
1523 PyThreadState_Swap(save_tstate);
1524 if (tstate == NULL) {
1525 /* Since no new thread state was created, there is no exception to
1526 propagate; raise a fresh one after swapping in the old thread
1527 state. */
1528 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
1529 return NULL;
1530 }
1531 return _get_id(tstate->interp);
1532}
1533
1534PyDoc_STRVAR(create_doc,
1535"create() -> ID\n\
1536\n\
1537Create a new interpreter and return a unique generated ID.");
1538
1539
1540static PyObject *
1541interp_destroy(PyObject *self, PyObject *args)
1542{
1543 PyObject *id;
1544 if (!PyArg_UnpackTuple(args, "destroy", 1, 1, &id)) {
1545 return NULL;
1546 }
1547 if (!PyLong_Check(id)) {
1548 PyErr_SetString(PyExc_TypeError, "ID must be an int");
1549 return NULL;
1550 }
1551
1552 // Look up the interpreter.
1553 PyInterpreterState *interp = _look_up(id);
1554 if (interp == NULL) {
1555 return NULL;
1556 }
1557
1558 // Ensure we don't try to destroy the current interpreter.
1559 PyInterpreterState *current = _get_current();
1560 if (current == NULL) {
1561 return NULL;
1562 }
1563 if (interp == current) {
1564 PyErr_SetString(PyExc_RuntimeError,
1565 "cannot destroy the current interpreter");
1566 return NULL;
1567 }
1568
1569 // Ensure the interpreter isn't running.
1570 /* XXX We *could* support destroying a running interpreter but
1571 aren't going to worry about it for now. */
1572 if (_ensure_not_running(interp) < 0) {
1573 return NULL;
1574 }
1575
1576 // Destroy the interpreter.
1577 //PyInterpreterState_Delete(interp);
1578 PyThreadState *tstate, *save_tstate;
1579 tstate = PyInterpreterState_ThreadHead(interp);
1580 save_tstate = PyThreadState_Swap(tstate);
1581 Py_EndInterpreter(tstate);
1582 PyThreadState_Swap(save_tstate);
1583
1584 Py_RETURN_NONE;
1585}
1586
1587PyDoc_STRVAR(destroy_doc,
1588"destroy(ID)\n\
1589\n\
1590Destroy the identified interpreter.\n\
1591\n\
1592Attempting to destroy the current interpreter results in a RuntimeError.\n\
1593So does an unrecognized ID.");
1594
1595
1596static PyObject *
1597interp_list_all(PyObject *self)
1598{
1599 PyObject *ids, *id;
1600 PyInterpreterState *interp;
1601
1602 ids = PyList_New(0);
1603 if (ids == NULL) {
1604 return NULL;
1605 }
1606
1607 interp = PyInterpreterState_Head();
1608 while (interp != NULL) {
1609 id = _get_id(interp);
1610 if (id == NULL) {
1611 Py_DECREF(ids);
1612 return NULL;
1613 }
1614 // insert at front of list
1615 if (PyList_Insert(ids, 0, id) < 0) {
1616 Py_DECREF(ids);
1617 return NULL;
1618 }
1619
1620 interp = PyInterpreterState_Next(interp);
1621 }
1622
1623 return ids;
1624}
1625
1626PyDoc_STRVAR(list_all_doc,
1627"list_all() -> [ID]\n\
1628\n\
1629Return a list containing the ID of every existing interpreter.");
1630
1631
1632static PyObject *
1633interp_get_current(PyObject *self)
1634{
1635 PyInterpreterState *interp =_get_current();
1636 if (interp == NULL) {
1637 return NULL;
1638 }
1639 return _get_id(interp);
1640}
1641
1642PyDoc_STRVAR(get_current_doc,
1643"get_current() -> ID\n\
1644\n\
1645Return the ID of current interpreter.");
1646
1647
1648static PyObject *
1649interp_get_main(PyObject *self)
1650{
1651 // Currently, 0 is always the main interpreter.
1652 return PyLong_FromLongLong(0);
1653}
1654
1655PyDoc_STRVAR(get_main_doc,
1656"get_main() -> ID\n\
1657\n\
1658Return the ID of main interpreter.");
1659
1660
1661static PyObject *
1662interp_run_string(PyObject *self, PyObject *args)
1663{
1664 PyObject *id, *code;
1665 PyObject *shared = NULL;
1666 if (!PyArg_UnpackTuple(args, "run_string", 2, 3, &id, &code, &shared)) {
1667 return NULL;
1668 }
1669 if (!PyLong_Check(id)) {
1670 PyErr_SetString(PyExc_TypeError, "first arg (ID) must be an int");
1671 return NULL;
1672 }
1673 if (!PyUnicode_Check(code)) {
1674 PyErr_SetString(PyExc_TypeError,
1675 "second arg (code) must be a string");
1676 return NULL;
1677 }
1678
1679 // Look up the interpreter.
1680 PyInterpreterState *interp = _look_up(id);
1681 if (interp == NULL) {
1682 return NULL;
1683 }
1684
1685 // Extract code.
1686 Py_ssize_t size;
1687 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
1688 if (codestr == NULL) {
1689 return NULL;
1690 }
1691 if (strlen(codestr) != (size_t)size) {
1692 PyErr_SetString(PyExc_ValueError,
1693 "source code string cannot contain null bytes");
1694 return NULL;
1695 }
1696
1697 // Run the code in the interpreter.
1698 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
1699 return NULL;
1700 }
1701 Py_RETURN_NONE;
1702}
1703
1704PyDoc_STRVAR(run_string_doc,
1705"run_string(ID, sourcetext)\n\
1706\n\
1707Execute the provided string in the identified interpreter.\n\
1708\n\
1709See PyRun_SimpleStrings.");
1710
1711
1712static PyObject *
1713object_is_shareable(PyObject *self, PyObject *args)
1714{
1715 PyObject *obj;
1716 if (!PyArg_UnpackTuple(args, "is_shareable", 1, 1, &obj)) {
1717 return NULL;
1718 }
1719 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
1720 Py_RETURN_TRUE;
1721 }
1722 PyErr_Clear();
1723 Py_RETURN_FALSE;
1724}
1725
1726PyDoc_STRVAR(is_shareable_doc,
1727"is_shareable(obj) -> bool\n\
1728\n\
1729Return True if the object's data may be shared between interpreters and\n\
1730False otherwise.");
1731
1732
1733static PyObject *
1734interp_is_running(PyObject *self, PyObject *args)
1735{
1736 PyObject *id;
1737 if (!PyArg_UnpackTuple(args, "is_running", 1, 1, &id)) {
1738 return NULL;
1739 }
1740 if (!PyLong_Check(id)) {
1741 PyErr_SetString(PyExc_TypeError, "ID must be an int");
1742 return NULL;
1743 }
1744
1745 PyInterpreterState *interp = _look_up(id);
1746 if (interp == NULL) {
1747 return NULL;
1748 }
1749 int is_running = _is_running(interp);
1750 if (is_running < 0) {
1751 return NULL;
1752 }
1753 if (is_running) {
1754 Py_RETURN_TRUE;
1755 }
1756 Py_RETURN_FALSE;
1757}
1758
1759PyDoc_STRVAR(is_running_doc,
1760"is_running(id) -> bool\n\
1761\n\
1762Return whether or not the identified interpreter is running.");
1763
1764static PyObject *
1765channel_create(PyObject *self)
1766{
1767 int64_t cid = _channel_create(&_globals.channels);
1768 if (cid < 0) {
1769 return NULL;
1770 }
1771 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
1772 &_globals.channels, 0);
1773 if (id == NULL) {
1774 if (_channel_destroy(&_globals.channels, cid) != 0) {
1775 // XXX issue a warning?
1776 }
1777 return NULL;
1778 }
1779 assert(((channelid *)id)->channels != NULL);
1780 return id;
1781}
1782
1783PyDoc_STRVAR(channel_create_doc,
1784"channel_create() -> ID\n\
1785\n\
1786Create a new cross-interpreter channel and return a unique generated ID.");
1787
1788static PyObject *
1789channel_destroy(PyObject *self, PyObject *args)
1790{
1791 PyObject *id;
1792 if (!PyArg_UnpackTuple(args, "channel_destroy", 1, 1, &id)) {
1793 return NULL;
1794 }
1795 int64_t cid = _coerce_id(id);
1796 if (cid < 0) {
1797 return NULL;
1798 }
1799
1800 if (_channel_destroy(&_globals.channels, cid) != 0) {
1801 return NULL;
1802 }
1803 Py_RETURN_NONE;
1804}
1805
1806PyDoc_STRVAR(channel_destroy_doc,
1807"channel_destroy(ID)\n\
1808\n\
1809Close and finalize the channel. Afterward attempts to use the channel\n\
1810will behave as though it never existed.");
1811
1812static PyObject *
1813channel_list_all(PyObject *self)
1814{
1815 int64_t count = 0;
1816 int64_t *cids = _channels_list_all(&_globals.channels, &count);
1817 if (cids == NULL) {
1818 if (count == 0) {
1819 return PyList_New(0);
1820 }
1821 return NULL;
1822 }
1823 PyObject *ids = PyList_New((Py_ssize_t)count);
1824 if (ids == NULL) {
1825 // XXX free cids
1826 return NULL;
1827 }
1828 for (int64_t i=0; i < count; cids++, i++) {
1829 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cids, 0,
1830 &_globals.channels, 0);
1831 if (id == NULL) {
1832 Py_DECREF(ids);
1833 ids = NULL;
1834 break;
1835 }
1836 PyList_SET_ITEM(ids, i, id);
1837 }
1838 // XXX free cids
1839 return ids;
1840}
1841
1842PyDoc_STRVAR(channel_list_all_doc,
1843"channel_list_all() -> [ID]\n\
1844\n\
1845Return the list of all IDs for active channels.");
1846
1847static PyObject *
1848channel_send(PyObject *self, PyObject *args)
1849{
1850 PyObject *id;
1851 PyObject *obj;
1852 if (!PyArg_UnpackTuple(args, "channel_send", 2, 2, &id, &obj)) {
1853 return NULL;
1854 }
1855 int64_t cid = _coerce_id(id);
1856 if (cid < 0) {
1857 return NULL;
1858 }
1859
1860 if (_channel_send(&_globals.channels, cid, obj) != 0) {
1861 return NULL;
1862 }
1863 Py_RETURN_NONE;
1864}
1865
1866PyDoc_STRVAR(channel_send_doc,
1867"channel_send(ID, obj)\n\
1868\n\
1869Add the object's data to the channel's queue.");
1870
1871static PyObject *
1872channel_recv(PyObject *self, PyObject *args)
1873{
1874 PyObject *id;
1875 if (!PyArg_UnpackTuple(args, "channel_recv", 1, 1, &id)) {
1876 return NULL;
1877 }
1878 int64_t cid = _coerce_id(id);
1879 if (cid < 0) {
1880 return NULL;
1881 }
1882
1883 return _channel_recv(&_globals.channels, cid);
1884}
1885
1886PyDoc_STRVAR(channel_recv_doc,
1887"channel_recv(ID) -> obj\n\
1888\n\
1889Return a new object from the data at the from of the channel's queue.");
1890
1891static PyObject *
1892channel_close(PyObject *self, PyObject *args, PyObject *kwds)
1893{
1894 PyObject *id;
1895 if (!PyArg_UnpackTuple(args, "channel_recv", 1, 1, &id)) {
1896 return NULL;
1897 }
1898 int64_t cid = _coerce_id(id);
1899 if (cid < 0) {
1900 return NULL;
1901 }
1902
1903 if (_channel_close(&_globals.channels, cid) != 0) {
1904 return NULL;
1905 }
1906 Py_RETURN_NONE;
1907}
1908
1909PyDoc_STRVAR(channel_close_doc,
1910"channel_close(ID)\n\
1911\n\
1912Close the channel for all interpreters. Once the channel's ID has\n\
1913no more ref counts the channel will be destroyed.");
1914
1915static PyObject *
1916channel_drop_interpreter(PyObject *self, PyObject *args, PyObject *kwds)
1917{
1918 // Note that only the current interpreter is affected.
1919 static char *kwlist[] = {"id", "send", "recv"};
1920 PyObject *id;
1921 int send = -1;
1922 int recv = -1;
1923 if (!PyArg_ParseTupleAndKeywords(args, kwds,
1924 "O|$pp:channel_drop_interpreter", kwlist,
1925 &id, &send, &recv))
1926 return NULL;
1927
1928 int64_t cid = _coerce_id(id);
1929 if (cid < 0) {
1930 return NULL;
1931 }
1932 if (send < 0 && recv < 0) {
1933 send = 1;
1934 recv = 1;
1935 }
1936 else {
1937 if (send < 0) {
1938 send = 0;
1939 }
1940 if (recv < 0) {
1941 recv = 0;
1942 }
1943 }
1944 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
1945 return NULL;
1946 }
1947 Py_RETURN_NONE;
1948}
1949
1950PyDoc_STRVAR(channel_drop_interpreter_doc,
1951"channel_drop_interpreter(ID, *, send=None, recv=None)\n\
1952\n\
1953Close the channel for the current interpreter. 'send' and 'recv'\n\
1954(bool) may be used to indicate the ends to close. By default both\n\
1955ends are closed. Closing an already closed end is a noop.");
1956
1957static PyObject *
1958channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
1959{
1960 return channelid_new(&ChannelIDtype, args, kwds);
1961}
1962
1963static PyMethodDef module_functions[] = {
1964 {"create", (PyCFunction)interp_create,
1965 METH_VARARGS, create_doc},
1966 {"destroy", (PyCFunction)interp_destroy,
1967 METH_VARARGS, destroy_doc},
1968 {"list_all", (PyCFunction)interp_list_all,
1969 METH_NOARGS, list_all_doc},
1970 {"get_current", (PyCFunction)interp_get_current,
1971 METH_NOARGS, get_current_doc},
1972 {"get_main", (PyCFunction)interp_get_main,
1973 METH_NOARGS, get_main_doc},
1974 {"is_running", (PyCFunction)interp_is_running,
1975 METH_VARARGS, is_running_doc},
1976 {"run_string", (PyCFunction)interp_run_string,
1977 METH_VARARGS, run_string_doc},
1978
1979 {"is_shareable", (PyCFunction)object_is_shareable,
1980 METH_VARARGS, is_shareable_doc},
1981
1982 {"channel_create", (PyCFunction)channel_create,
1983 METH_NOARGS, channel_create_doc},
1984 {"channel_destroy", (PyCFunction)channel_destroy,
1985 METH_VARARGS, channel_destroy_doc},
1986 {"channel_list_all", (PyCFunction)channel_list_all,
1987 METH_NOARGS, channel_list_all_doc},
1988 {"channel_send", (PyCFunction)channel_send,
1989 METH_VARARGS, channel_send_doc},
1990 {"channel_recv", (PyCFunction)channel_recv,
1991 METH_VARARGS, channel_recv_doc},
1992 {"channel_close", (PyCFunction)channel_close,
1993 METH_VARARGS, channel_close_doc},
1994 {"channel_drop_interpreter", (PyCFunction)channel_drop_interpreter,
1995 METH_VARARGS | METH_KEYWORDS, channel_drop_interpreter_doc},
1996 {"_channel_id", (PyCFunction)channel__channel_id,
1997 METH_VARARGS | METH_KEYWORDS, NULL},
1998
1999 {NULL, NULL} /* sentinel */
2000};
2001
2002
2003/* initialization function */
2004
2005PyDoc_STRVAR(module_doc,
2006"This module provides primitive operations to manage Python interpreters.\n\
2007The 'interpreters' module provides a more convenient interface.");
2008
2009static struct PyModuleDef interpretersmodule = {
2010 PyModuleDef_HEAD_INIT,
2011 "_xxsubinterpreters", /* m_name */
2012 module_doc, /* m_doc */
2013 -1, /* m_size */
2014 module_functions, /* m_methods */
2015 NULL, /* m_slots */
2016 NULL, /* m_traverse */
2017 NULL, /* m_clear */
2018 NULL /* m_free */
2019};
2020
2021
2022PyMODINIT_FUNC
2023PyInit__xxsubinterpreters(void)
2024{
2025 if (_init_globals() != 0) {
2026 return NULL;
2027 }
2028
2029 /* Initialize types */
2030 ChannelIDtype.tp_base = &PyLong_Type;
2031 if (PyType_Ready(&ChannelIDtype) != 0) {
2032 return NULL;
2033 }
2034
2035 /* Create the module */
2036 PyObject *module = PyModule_Create(&interpretersmodule);
2037 if (module == NULL) {
2038 return NULL;
2039 }
2040
2041 /* Add exception types */
2042 PyObject *ns = PyModule_GetDict(module); // borrowed
2043 if (interp_exceptions_init(ns) != 0) {
2044 return NULL;
2045 }
2046 if (channel_exceptions_init(ns) != 0) {
2047 return NULL;
2048 }
2049
2050 /* Add other types */
2051 Py_INCREF(&ChannelIDtype);
2052 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2053 return NULL;
2054 }
2055
2056 if (_PyCrossInterpreterData_Register_Class(&ChannelIDtype, _channelid_shared)) {
2057 return NULL;
2058 }
2059
2060 return module;
2061}