blob: 33509ef4ded5667876125342cb751db21f3367a4 [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"
Victor Stinner621cebe2018-11-12 16:53:38 +01007#include "pycore_pystate.h"
Eric Snow7f8bfc92018-01-29 18:23:44 -07008
9
Eric Snow4e9da0d2018-02-02 21:49:49 -070010static char *
11_copy_raw_string(PyObject *strobj)
12{
13 const char *str = PyUnicode_AsUTF8(strobj);
14 if (str == NULL) {
15 return NULL;
16 }
17 char *copied = PyMem_Malloc(strlen(str)+1);
Alexey Izbyshevc5839192018-08-22 21:27:32 +030018 if (copied == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070019 PyErr_NoMemory();
20 return NULL;
21 }
22 strcpy(copied, str);
23 return copied;
24}
25
Eric Snow7f8bfc92018-01-29 18:23:44 -070026static PyInterpreterState *
27_get_current(void)
28{
Victor Stinnercaba55b2018-08-03 15:33:52 +020029 // _PyInterpreterState_Get() aborts if lookup fails, so don't need
Eric Snow7f8bfc92018-01-29 18:23:44 -070030 // to check the result for NULL.
Victor Stinnercaba55b2018-08-03 15:33:52 +020031 return _PyInterpreterState_Get();
Eric Snow7f8bfc92018-01-29 18:23:44 -070032}
33
34static int64_t
Eric Snow6854e802018-06-01 16:26:01 -060035_coerce_id(PyObject *orig)
Eric Snow7f8bfc92018-01-29 18:23:44 -070036{
Eric Snow6854e802018-06-01 16:26:01 -060037 PyObject *pyid = PyNumber_Long(orig);
38 if (pyid == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -070039 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
Eric Snow6854e802018-06-01 16:26:01 -060040 PyErr_Format(PyExc_TypeError,
41 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070042 }
43 else {
Eric Snow6854e802018-06-01 16:26:01 -060044 PyErr_Format(PyExc_ValueError,
45 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070046 }
47 return -1;
48 }
Eric Snow6854e802018-06-01 16:26:01 -060049 int64_t id = PyLong_AsLongLong(pyid);
50 Py_DECREF(pyid);
51 if (id == -1 && PyErr_Occurred() != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070052 if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
Eric Snow6854e802018-06-01 16:26:01 -060053 PyErr_Format(PyExc_ValueError,
54 "'id' must be a non-negative int, got %R", orig);
Eric Snow4e9da0d2018-02-02 21:49:49 -070055 }
Eric Snow7f8bfc92018-01-29 18:23:44 -070056 return -1;
57 }
Eric Snow6854e802018-06-01 16:26:01 -060058 if (id < 0) {
59 PyErr_Format(PyExc_ValueError,
60 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070061 return -1;
62 }
Eric Snow6854e802018-06-01 16:26:01 -060063 return id;
Eric Snow7f8bfc92018-01-29 18:23:44 -070064}
65
Eric Snow4e9da0d2018-02-02 21:49:49 -070066
Eric Snow7f8bfc92018-01-29 18:23:44 -070067/* data-sharing-specific code ***********************************************/
68
Eric Snow4e9da0d2018-02-02 21:49:49 -070069struct _sharednsitem {
70 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -070071 _PyCrossInterpreterData data;
Eric Snow4e9da0d2018-02-02 21:49:49 -070072};
Eric Snow7f8bfc92018-01-29 18:23:44 -070073
Eric Snow4e9da0d2018-02-02 21:49:49 -070074static int
75_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
Eric Snow7f8bfc92018-01-29 18:23:44 -070076{
Eric Snow4e9da0d2018-02-02 21:49:49 -070077 item->name = _copy_raw_string(key);
78 if (item->name == NULL) {
79 return -1;
Eric Snow7f8bfc92018-01-29 18:23:44 -070080 }
Eric Snow4e9da0d2018-02-02 21:49:49 -070081 if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
82 return -1;
83 }
84 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -070085}
86
Eric Snow4e9da0d2018-02-02 21:49:49 -070087static void
88_sharednsitem_clear(struct _sharednsitem *item)
89{
90 if (item->name != NULL) {
91 PyMem_Free(item->name);
92 }
93 _PyCrossInterpreterData_Release(&item->data);
94}
95
96static int
97_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
98{
99 PyObject *name = PyUnicode_FromString(item->name);
100 if (name == NULL) {
101 return -1;
102 }
103 PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
104 if (value == NULL) {
105 Py_DECREF(name);
106 return -1;
107 }
108 int res = PyDict_SetItem(ns, name, value);
109 Py_DECREF(name);
110 Py_DECREF(value);
111 return res;
112}
113
114typedef struct _sharedns {
115 Py_ssize_t len;
116 struct _sharednsitem* items;
117} _sharedns;
118
119static _sharedns *
120_sharedns_new(Py_ssize_t len)
121{
122 _sharedns *shared = PyMem_NEW(_sharedns, 1);
123 if (shared == NULL) {
124 PyErr_NoMemory();
125 return NULL;
126 }
127 shared->len = len;
128 shared->items = PyMem_NEW(struct _sharednsitem, len);
129 if (shared->items == NULL) {
130 PyErr_NoMemory();
131 PyMem_Free(shared);
132 return NULL;
133 }
134 return shared;
135}
136
137static void
138_sharedns_free(_sharedns *shared)
139{
140 for (Py_ssize_t i=0; i < shared->len; i++) {
141 _sharednsitem_clear(&shared->items[i]);
142 }
143 PyMem_Free(shared->items);
144 PyMem_Free(shared);
145}
146
147static _sharedns *
148_get_shared_ns(PyObject *shareable)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700149{
150 if (shareable == NULL || shareable == Py_None) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700151 return NULL;
152 }
153 Py_ssize_t len = PyDict_Size(shareable);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700154 if (len == 0) {
155 return NULL;
156 }
157
Eric Snow4e9da0d2018-02-02 21:49:49 -0700158 _sharedns *shared = _sharedns_new(len);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700159 if (shared == NULL) {
160 return NULL;
161 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700162 Py_ssize_t pos = 0;
163 for (Py_ssize_t i=0; i < len; i++) {
164 PyObject *key, *value;
165 if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
166 break;
167 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700168 if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700169 break;
170 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700171 }
172 if (PyErr_Occurred()) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700173 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700174 return NULL;
175 }
176 return shared;
177}
178
179static int
Eric Snow4e9da0d2018-02-02 21:49:49 -0700180_sharedns_apply(_sharedns *shared, PyObject *ns)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700181{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700182 for (Py_ssize_t i=0; i < shared->len; i++) {
183 if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
184 return -1;
185 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700186 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700187 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700188}
189
190// Ultimately we'd like to preserve enough information about the
191// exception and traceback that we could re-constitute (or at least
192// simulate, a la traceback.TracebackException), and even chain, a copy
193// of the exception in the calling interpreter.
194
195typedef struct _sharedexception {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700196 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700197 char *msg;
198} _sharedexception;
199
200static _sharedexception *
Eric Snow4e9da0d2018-02-02 21:49:49 -0700201_sharedexception_new(void)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700202{
203 _sharedexception *err = PyMem_NEW(_sharedexception, 1);
204 if (err == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700205 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700206 return NULL;
207 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700208 err->name = NULL;
209 err->msg = NULL;
210 return err;
211}
212
213static void
214_sharedexception_clear(_sharedexception *exc)
215{
216 if (exc->name != NULL) {
217 PyMem_Free(exc->name);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700218 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700219 if (exc->msg != NULL) {
220 PyMem_Free(exc->msg);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700221 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700222}
223
224static void
225_sharedexception_free(_sharedexception *exc)
226{
227 _sharedexception_clear(exc);
228 PyMem_Free(exc);
229}
230
231static _sharedexception *
232_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
233{
234 assert(exctype != NULL);
235 char *failure = NULL;
236
237 _sharedexception *err = _sharedexception_new();
238 if (err == NULL) {
239 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700240 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700241
242 PyObject *name = PyUnicode_FromFormat("%S", exctype);
243 if (name == NULL) {
244 failure = "unable to format exception type name";
245 goto finally;
246 }
247 err->name = _copy_raw_string(name);
248 Py_DECREF(name);
249 if (err->name == NULL) {
250 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
251 failure = "out of memory copying exception type name";
252 }
253 failure = "unable to encode and copy exception type name";
254 goto finally;
255 }
256
257 if (exc != NULL) {
258 PyObject *msg = PyUnicode_FromFormat("%S", exc);
259 if (msg == NULL) {
260 failure = "unable to format exception message";
261 goto finally;
262 }
263 err->msg = _copy_raw_string(msg);
264 Py_DECREF(msg);
265 if (err->msg == NULL) {
266 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
267 failure = "out of memory copying exception message";
268 }
269 failure = "unable to encode and copy exception message";
270 goto finally;
271 }
272 }
273
274finally:
275 if (failure != NULL) {
276 PyErr_Clear();
277 if (err->name != NULL) {
278 PyMem_Free(err->name);
279 err->name = NULL;
280 }
281 err->msg = failure;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700282 }
283 return err;
284}
285
Eric Snow7f8bfc92018-01-29 18:23:44 -0700286static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700287_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700288{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700289 if (exc->name != NULL) {
290 if (exc->msg != NULL) {
291 PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
292 }
293 else {
294 PyErr_SetString(wrapperclass, exc->name);
295 }
296 }
297 else if (exc->msg != NULL) {
298 PyErr_SetString(wrapperclass, exc->msg);
299 }
300 else {
301 PyErr_SetNone(wrapperclass);
302 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700303}
304
Eric Snow4e9da0d2018-02-02 21:49:49 -0700305
306/* channel-specific code ****************************************************/
Eric Snow7f8bfc92018-01-29 18:23:44 -0700307
Eric Snow3ab01362018-05-17 10:27:09 -0400308#define CHANNEL_SEND 1
309#define CHANNEL_BOTH 0
310#define CHANNEL_RECV -1
311
Eric Snow7f8bfc92018-01-29 18:23:44 -0700312static PyObject *ChannelError;
313static PyObject *ChannelNotFoundError;
314static PyObject *ChannelClosedError;
315static PyObject *ChannelEmptyError;
Eric Snow3ab01362018-05-17 10:27:09 -0400316static PyObject *ChannelNotEmptyError;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700317
318static int
319channel_exceptions_init(PyObject *ns)
320{
321 // XXX Move the exceptions into per-module memory?
322
323 // A channel-related operation failed.
324 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
325 PyExc_RuntimeError, NULL);
326 if (ChannelError == NULL) {
327 return -1;
328 }
329 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
330 return -1;
331 }
332
333 // An operation tried to use a channel that doesn't exist.
334 ChannelNotFoundError = PyErr_NewException(
335 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
336 if (ChannelNotFoundError == NULL) {
337 return -1;
338 }
339 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
340 return -1;
341 }
342
343 // An operation tried to use a closed channel.
344 ChannelClosedError = PyErr_NewException(
345 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
346 if (ChannelClosedError == NULL) {
347 return -1;
348 }
349 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
350 return -1;
351 }
352
353 // An operation tried to pop from an empty channel.
354 ChannelEmptyError = PyErr_NewException(
355 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
356 if (ChannelEmptyError == NULL) {
357 return -1;
358 }
359 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
360 return -1;
361 }
362
Eric Snow3ab01362018-05-17 10:27:09 -0400363 // An operation tried to close a non-empty channel.
364 ChannelNotEmptyError = PyErr_NewException(
365 "_xxsubinterpreters.ChannelNotEmptyError", ChannelError, NULL);
366 if (ChannelNotEmptyError == NULL) {
367 return -1;
368 }
369 if (PyDict_SetItemString(ns, "ChannelNotEmptyError", ChannelNotEmptyError) != 0) {
370 return -1;
371 }
372
Eric Snow7f8bfc92018-01-29 18:23:44 -0700373 return 0;
374}
375
Eric Snow4e9da0d2018-02-02 21:49:49 -0700376/* the channel queue */
377
378struct _channelitem;
379
380typedef struct _channelitem {
381 _PyCrossInterpreterData *data;
382 struct _channelitem *next;
383} _channelitem;
384
385static _channelitem *
386_channelitem_new(void)
387{
388 _channelitem *item = PyMem_NEW(_channelitem, 1);
389 if (item == NULL) {
390 PyErr_NoMemory();
391 return NULL;
392 }
393 item->data = NULL;
394 item->next = NULL;
395 return item;
396}
397
398static void
399_channelitem_clear(_channelitem *item)
400{
401 if (item->data != NULL) {
402 _PyCrossInterpreterData_Release(item->data);
403 PyMem_Free(item->data);
404 item->data = NULL;
405 }
406 item->next = NULL;
407}
408
409static void
410_channelitem_free(_channelitem *item)
411{
412 _channelitem_clear(item);
413 PyMem_Free(item);
414}
415
416static void
417_channelitem_free_all(_channelitem *item)
418{
419 while (item != NULL) {
420 _channelitem *last = item;
421 item = item->next;
422 _channelitem_free(last);
423 }
424}
425
426static _PyCrossInterpreterData *
427_channelitem_popped(_channelitem *item)
428{
429 _PyCrossInterpreterData *data = item->data;
430 item->data = NULL;
431 _channelitem_free(item);
432 return data;
433}
434
435typedef struct _channelqueue {
436 int64_t count;
437 _channelitem *first;
438 _channelitem *last;
439} _channelqueue;
440
441static _channelqueue *
442_channelqueue_new(void)
443{
444 _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
445 if (queue == NULL) {
446 PyErr_NoMemory();
447 return NULL;
448 }
449 queue->count = 0;
450 queue->first = NULL;
451 queue->last = NULL;
452 return queue;
453}
454
455static void
456_channelqueue_clear(_channelqueue *queue)
457{
458 _channelitem_free_all(queue->first);
459 queue->count = 0;
460 queue->first = NULL;
461 queue->last = NULL;
462}
463
464static void
465_channelqueue_free(_channelqueue *queue)
466{
467 _channelqueue_clear(queue);
468 PyMem_Free(queue);
469}
470
471static int
472_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
473{
474 _channelitem *item = _channelitem_new();
475 if (item == NULL) {
476 return -1;
477 }
478 item->data = data;
479
480 queue->count += 1;
481 if (queue->first == NULL) {
482 queue->first = item;
483 }
484 else {
485 queue->last->next = item;
486 }
487 queue->last = item;
488 return 0;
489}
490
491static _PyCrossInterpreterData *
492_channelqueue_get(_channelqueue *queue)
493{
494 _channelitem *item = queue->first;
495 if (item == NULL) {
496 return NULL;
497 }
498 queue->first = item->next;
499 if (queue->last == item) {
500 queue->last = NULL;
501 }
502 queue->count -= 1;
503
504 return _channelitem_popped(item);
505}
506
507/* channel-interpreter associations */
508
Eric Snow7f8bfc92018-01-29 18:23:44 -0700509struct _channelend;
510
511typedef struct _channelend {
512 struct _channelend *next;
513 int64_t interp;
514 int open;
515} _channelend;
516
517static _channelend *
518_channelend_new(int64_t interp)
519{
520 _channelend *end = PyMem_NEW(_channelend, 1);
521 if (end == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700522 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700523 return NULL;
524 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700525 end->next = NULL;
526 end->interp = interp;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700527 end->open = 1;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700528 return end;
529}
530
531static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700532_channelend_free(_channelend *end)
533{
534 PyMem_Free(end);
535}
536
537static void
538_channelend_free_all(_channelend *end)
539{
Eric Snow7f8bfc92018-01-29 18:23:44 -0700540 while (end != NULL) {
541 _channelend *last = end;
542 end = end->next;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700543 _channelend_free(last);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700544 }
545}
546
547static _channelend *
548_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
549{
550 _channelend *prev = NULL;
551 _channelend *end = first;
552 while (end != NULL) {
553 if (end->interp == interp) {
554 break;
555 }
556 prev = end;
557 end = end->next;
558 }
559 if (pprev != NULL) {
560 *pprev = prev;
561 }
562 return end;
563}
564
Eric Snow4e9da0d2018-02-02 21:49:49 -0700565typedef struct _channelassociations {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700566 // Note that the list entries are never removed for interpreter
567 // for which the channel is closed. This should be a problem in
568 // practice. Also, a channel isn't automatically closed when an
569 // interpreter is destroyed.
570 int64_t numsendopen;
571 int64_t numrecvopen;
572 _channelend *send;
573 _channelend *recv;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700574} _channelends;
575
576static _channelends *
577_channelends_new(void)
578{
579 _channelends *ends = PyMem_NEW(_channelends, 1);
580 if (ends== NULL) {
581 return NULL;
582 }
583 ends->numsendopen = 0;
584 ends->numrecvopen = 0;
585 ends->send = NULL;
586 ends->recv = NULL;
587 return ends;
588}
589
590static void
591_channelends_clear(_channelends *ends)
592{
593 _channelend_free_all(ends->send);
594 ends->send = NULL;
595 ends->numsendopen = 0;
596
597 _channelend_free_all(ends->recv);
598 ends->recv = NULL;
599 ends->numrecvopen = 0;
600}
601
602static void
603_channelends_free(_channelends *ends)
604{
605 _channelends_clear(ends);
606 PyMem_Free(ends);
607}
608
609static _channelend *
610_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
611 int send)
612{
613 _channelend *end = _channelend_new(interp);
614 if (end == NULL) {
615 return NULL;
616 }
617
618 if (prev == NULL) {
619 if (send) {
620 ends->send = end;
621 }
622 else {
623 ends->recv = end;
624 }
625 }
626 else {
627 prev->next = end;
628 }
629 if (send) {
630 ends->numsendopen += 1;
631 }
632 else {
633 ends->numrecvopen += 1;
634 }
635 return end;
636}
637
638static int
639_channelends_associate(_channelends *ends, int64_t interp, int send)
640{
641 _channelend *prev;
642 _channelend *end = _channelend_find(send ? ends->send : ends->recv,
643 interp, &prev);
644 if (end != NULL) {
645 if (!end->open) {
646 PyErr_SetString(ChannelClosedError, "channel already closed");
647 return -1;
648 }
649 // already associated
650 return 0;
651 }
652 if (_channelends_add(ends, prev, interp, send) == NULL) {
653 return -1;
654 }
655 return 0;
656}
657
658static int
659_channelends_is_open(_channelends *ends)
660{
661 if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
662 return 1;
663 }
664 if (ends->send == NULL && ends->recv == NULL) {
665 return 1;
666 }
667 return 0;
668}
669
670static void
671_channelends_close_end(_channelends *ends, _channelend *end, int send)
672{
673 end->open = 0;
674 if (send) {
675 ends->numsendopen -= 1;
676 }
677 else {
678 ends->numrecvopen -= 1;
679 }
680}
681
682static int
683_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
684{
685 _channelend *prev;
686 _channelend *end;
687 if (which >= 0) { // send/both
688 end = _channelend_find(ends->send, interp, &prev);
689 if (end == NULL) {
690 // never associated so add it
691 end = _channelends_add(ends, prev, interp, 1);
692 if (end == NULL) {
693 return -1;
694 }
695 }
696 _channelends_close_end(ends, end, 1);
697 }
698 if (which <= 0) { // recv/both
699 end = _channelend_find(ends->recv, interp, &prev);
700 if (end == NULL) {
701 // never associated so add it
702 end = _channelends_add(ends, prev, interp, 0);
703 if (end == NULL) {
704 return -1;
705 }
706 }
707 _channelends_close_end(ends, end, 0);
708 }
709 return 0;
710}
711
712static void
Eric Snow3ab01362018-05-17 10:27:09 -0400713_channelends_close_all(_channelends *ends, int which, int force)
Eric Snow4e9da0d2018-02-02 21:49:49 -0700714{
Eric Snow3ab01362018-05-17 10:27:09 -0400715 // XXX Handle the ends.
716 // XXX Handle force is True.
717
Eric Snow4e9da0d2018-02-02 21:49:49 -0700718 // Ensure all the "send"-associated interpreters are closed.
719 _channelend *end;
720 for (end = ends->send; end != NULL; end = end->next) {
721 _channelends_close_end(ends, end, 1);
722 }
723
724 // Ensure all the "recv"-associated interpreters are closed.
725 for (end = ends->recv; end != NULL; end = end->next) {
726 _channelends_close_end(ends, end, 0);
727 }
728}
729
730/* channels */
731
732struct _channel;
Eric Snow3ab01362018-05-17 10:27:09 -0400733struct _channel_closing;
734static void _channel_clear_closing(struct _channel *);
735static void _channel_finish_closing(struct _channel *);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700736
737typedef struct _channel {
738 PyThread_type_lock mutex;
739 _channelqueue *queue;
740 _channelends *ends;
741 int open;
Eric Snow3ab01362018-05-17 10:27:09 -0400742 struct _channel_closing *closing;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700743} _PyChannelState;
744
745static _PyChannelState *
746_channel_new(void)
747{
748 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
749 if (chan == NULL) {
750 return NULL;
751 }
752 chan->mutex = PyThread_allocate_lock();
753 if (chan->mutex == NULL) {
754 PyMem_Free(chan);
755 PyErr_SetString(ChannelError,
756 "can't initialize mutex for new channel");
757 return NULL;
758 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700759 chan->queue = _channelqueue_new();
760 if (chan->queue == NULL) {
761 PyMem_Free(chan);
762 return NULL;
763 }
764 chan->ends = _channelends_new();
765 if (chan->ends == NULL) {
766 _channelqueue_free(chan->queue);
767 PyMem_Free(chan);
768 return NULL;
769 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700770 chan->open = 1;
Eric Snow3ab01362018-05-17 10:27:09 -0400771 chan->closing = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700772 return chan;
773}
774
Eric Snow4e9da0d2018-02-02 21:49:49 -0700775static void
776_channel_free(_PyChannelState *chan)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700777{
Eric Snow3ab01362018-05-17 10:27:09 -0400778 _channel_clear_closing(chan);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700779 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
780 _channelqueue_free(chan->queue);
781 _channelends_free(chan->ends);
782 PyThread_release_lock(chan->mutex);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700783
Eric Snow4e9da0d2018-02-02 21:49:49 -0700784 PyThread_free_lock(chan->mutex);
785 PyMem_Free(chan);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700786}
787
Eric Snow4e9da0d2018-02-02 21:49:49 -0700788static int
789_channel_add(_PyChannelState *chan, int64_t interp,
790 _PyCrossInterpreterData *data)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700791{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700792 int res = -1;
793 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
794
Eric Snow7f8bfc92018-01-29 18:23:44 -0700795 if (!chan->open) {
796 PyErr_SetString(ChannelClosedError, "channel closed");
Eric Snow4e9da0d2018-02-02 21:49:49 -0700797 goto done;
798 }
799 if (_channelends_associate(chan->ends, interp, 1) != 0) {
800 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700801 }
802
Eric Snow4e9da0d2018-02-02 21:49:49 -0700803 if (_channelqueue_put(chan->queue, data) != 0) {
804 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700805 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700806
807 res = 0;
808done:
809 PyThread_release_lock(chan->mutex);
810 return res;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700811}
812
Eric Snow4e9da0d2018-02-02 21:49:49 -0700813static _PyCrossInterpreterData *
814_channel_next(_PyChannelState *chan, int64_t interp)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700815{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700816 _PyCrossInterpreterData *data = NULL;
817 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
818
819 if (!chan->open) {
820 PyErr_SetString(ChannelClosedError, "channel closed");
821 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700822 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700823 if (_channelends_associate(chan->ends, interp, 0) != 0) {
824 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700825 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700826
827 data = _channelqueue_get(chan->queue);
Eric Snow3ab01362018-05-17 10:27:09 -0400828 if (data == NULL && !PyErr_Occurred() && chan->closing != NULL) {
829 chan->open = 0;
830 }
831
Eric Snow4e9da0d2018-02-02 21:49:49 -0700832done:
833 PyThread_release_lock(chan->mutex);
Eric Snow3ab01362018-05-17 10:27:09 -0400834 if (chan->queue->count == 0) {
835 _channel_finish_closing(chan);
836 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700837 return data;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700838}
839
840static int
Eric Snow3ab01362018-05-17 10:27:09 -0400841_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700842{
843 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
844
845 int res = -1;
846 if (!chan->open) {
847 PyErr_SetString(ChannelClosedError, "channel already closed");
848 goto done;
849 }
850
Eric Snow3ab01362018-05-17 10:27:09 -0400851 if (_channelends_close_interpreter(chan->ends, interp, end) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700852 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700853 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700854 chan->open = _channelends_is_open(chan->ends);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700855
856 res = 0;
857done:
858 PyThread_release_lock(chan->mutex);
859 return res;
860}
861
862static int
Eric Snow3ab01362018-05-17 10:27:09 -0400863_channel_close_all(_PyChannelState *chan, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700864{
865 int res = -1;
866 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
867
868 if (!chan->open) {
869 PyErr_SetString(ChannelClosedError, "channel already closed");
870 goto done;
871 }
872
Eric Snow3ab01362018-05-17 10:27:09 -0400873 if (!force && chan->queue->count > 0) {
874 PyErr_SetString(ChannelNotEmptyError,
875 "may not be closed if not empty (try force=True)");
876 goto done;
877 }
878
Eric Snow7f8bfc92018-01-29 18:23:44 -0700879 chan->open = 0;
880
881 // We *could* also just leave these in place, since we've marked
882 // the channel as closed already.
Eric Snow3ab01362018-05-17 10:27:09 -0400883 _channelends_close_all(chan->ends, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700884
885 res = 0;
886done:
887 PyThread_release_lock(chan->mutex);
888 return res;
889}
890
Eric Snow4e9da0d2018-02-02 21:49:49 -0700891/* the set of channels */
Eric Snow7f8bfc92018-01-29 18:23:44 -0700892
893struct _channelref;
894
895typedef struct _channelref {
896 int64_t id;
897 _PyChannelState *chan;
898 struct _channelref *next;
899 Py_ssize_t objcount;
900} _channelref;
901
902static _channelref *
903_channelref_new(int64_t id, _PyChannelState *chan)
904{
905 _channelref *ref = PyMem_NEW(_channelref, 1);
906 if (ref == NULL) {
907 return NULL;
908 }
909 ref->id = id;
910 ref->chan = chan;
911 ref->next = NULL;
912 ref->objcount = 0;
913 return ref;
914}
915
Eric Snow4e9da0d2018-02-02 21:49:49 -0700916//static void
917//_channelref_clear(_channelref *ref)
918//{
919// ref->id = -1;
920// ref->chan = NULL;
921// ref->next = NULL;
922// ref->objcount = 0;
923//}
924
925static void
926_channelref_free(_channelref *ref)
927{
Eric Snow3ab01362018-05-17 10:27:09 -0400928 if (ref->chan != NULL) {
929 _channel_clear_closing(ref->chan);
930 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700931 //_channelref_clear(ref);
932 PyMem_Free(ref);
933}
934
Eric Snow7f8bfc92018-01-29 18:23:44 -0700935static _channelref *
936_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
937{
938 _channelref *prev = NULL;
939 _channelref *ref = first;
940 while (ref != NULL) {
941 if (ref->id == id) {
942 break;
943 }
944 prev = ref;
945 ref = ref->next;
946 }
947 if (pprev != NULL) {
948 *pprev = prev;
949 }
950 return ref;
951}
952
953typedef struct _channels {
954 PyThread_type_lock mutex;
955 _channelref *head;
956 int64_t numopen;
957 int64_t next_id;
958} _channels;
959
960static int
961_channels_init(_channels *channels)
962{
963 if (channels->mutex == NULL) {
964 channels->mutex = PyThread_allocate_lock();
965 if (channels->mutex == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700966 PyErr_SetString(ChannelError,
967 "can't initialize mutex for channel management");
968 return -1;
969 }
970 }
971 channels->head = NULL;
972 channels->numopen = 0;
973 channels->next_id = 0;
974 return 0;
975}
976
977static int64_t
978_channels_next_id(_channels *channels) // needs lock
979{
980 int64_t id = channels->next_id;
981 if (id < 0) {
982 /* overflow */
983 PyErr_SetString(ChannelError,
984 "failed to get a channel ID");
985 return -1;
986 }
987 channels->next_id += 1;
988 return id;
989}
990
991static _PyChannelState *
992_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
993{
994 _PyChannelState *chan = NULL;
995 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
996 if (pmutex != NULL) {
997 *pmutex = NULL;
998 }
999
1000 _channelref *ref = _channelref_find(channels->head, id, NULL);
1001 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001002 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001003 goto done;
1004 }
1005 if (ref->chan == NULL || !ref->chan->open) {
Eric Snowab4a1982018-06-13 08:02:39 -06001006 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001007 goto done;
1008 }
1009
1010 if (pmutex != NULL) {
1011 // The mutex will be closed by the caller.
1012 *pmutex = channels->mutex;
1013 }
1014
1015 chan = ref->chan;
1016done:
1017 if (pmutex == NULL || *pmutex == NULL) {
1018 PyThread_release_lock(channels->mutex);
1019 }
1020 return chan;
1021}
1022
1023static int64_t
1024_channels_add(_channels *channels, _PyChannelState *chan)
1025{
1026 int64_t cid = -1;
1027 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1028
1029 // Create a new ref.
1030 int64_t id = _channels_next_id(channels);
1031 if (id < 0) {
1032 goto done;
1033 }
1034 _channelref *ref = _channelref_new(id, chan);
1035 if (ref == NULL) {
1036 goto done;
1037 }
1038
1039 // Add it to the list.
1040 // We assume that the channel is a new one (not already in the list).
1041 ref->next = channels->head;
1042 channels->head = ref;
1043 channels->numopen += 1;
1044
1045 cid = id;
1046done:
1047 PyThread_release_lock(channels->mutex);
1048 return cid;
1049}
1050
Eric Snow3ab01362018-05-17 10:27:09 -04001051/* forward */
1052static int _channel_set_closing(struct _channelref *, PyThread_type_lock);
1053
Eric Snow7f8bfc92018-01-29 18:23:44 -07001054static int
Eric Snow3ab01362018-05-17 10:27:09 -04001055_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan,
1056 int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001057{
1058 int res = -1;
1059 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1060 if (pchan != NULL) {
1061 *pchan = NULL;
1062 }
1063
1064 _channelref *ref = _channelref_find(channels->head, cid, NULL);
1065 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001066 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001067 goto done;
1068 }
1069
1070 if (ref->chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001071 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001072 goto done;
1073 }
Eric Snow3ab01362018-05-17 10:27:09 -04001074 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001075 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001076 goto done;
1077 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001078 else {
Eric Snow3ab01362018-05-17 10:27:09 -04001079 if (_channel_close_all(ref->chan, end, force) != 0) {
1080 if (end == CHANNEL_SEND &&
1081 PyErr_ExceptionMatches(ChannelNotEmptyError)) {
1082 if (ref->chan->closing != NULL) {
Eric Snow6854e802018-06-01 16:26:01 -06001083 PyErr_Format(ChannelClosedError,
Eric Snowab4a1982018-06-13 08:02:39 -06001084 "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001085 goto done;
1086 }
1087 // Mark the channel as closing and return. The channel
1088 // will be cleaned up in _channel_next().
1089 PyErr_Clear();
1090 if (_channel_set_closing(ref, channels->mutex) != 0) {
1091 goto done;
1092 }
1093 if (pchan != NULL) {
1094 *pchan = ref->chan;
1095 }
1096 res = 0;
1097 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001098 goto done;
1099 }
1100 if (pchan != NULL) {
1101 *pchan = ref->chan;
1102 }
Eric Snow3ab01362018-05-17 10:27:09 -04001103 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001104 _channel_free(ref->chan);
1105 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001106 ref->chan = NULL;
1107 }
1108
1109 res = 0;
1110done:
1111 PyThread_release_lock(channels->mutex);
1112 return res;
1113}
1114
1115static void
1116_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1117 _PyChannelState **pchan)
1118{
1119 if (ref == channels->head) {
1120 channels->head = ref->next;
1121 }
1122 else {
1123 prev->next = ref->next;
1124 }
1125 channels->numopen -= 1;
1126
1127 if (pchan != NULL) {
1128 *pchan = ref->chan;
1129 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001130 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001131}
1132
1133static int
1134_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1135{
1136 int res = -1;
1137 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1138
1139 if (pchan != NULL) {
1140 *pchan = NULL;
1141 }
1142
1143 _channelref *prev = NULL;
1144 _channelref *ref = _channelref_find(channels->head, id, &prev);
1145 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001146 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001147 goto done;
1148 }
1149
1150 _channels_remove_ref(channels, ref, prev, pchan);
1151
1152 res = 0;
1153done:
1154 PyThread_release_lock(channels->mutex);
1155 return res;
1156}
1157
1158static int
1159_channels_add_id_object(_channels *channels, int64_t id)
1160{
1161 int res = -1;
1162 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1163
1164 _channelref *ref = _channelref_find(channels->head, id, NULL);
1165 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001166 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001167 goto done;
1168 }
1169 ref->objcount += 1;
1170
1171 res = 0;
1172done:
1173 PyThread_release_lock(channels->mutex);
1174 return res;
1175}
1176
1177static void
1178_channels_drop_id_object(_channels *channels, int64_t id)
1179{
1180 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1181
1182 _channelref *prev = NULL;
1183 _channelref *ref = _channelref_find(channels->head, id, &prev);
1184 if (ref == NULL) {
1185 // Already destroyed.
1186 goto done;
1187 }
1188 ref->objcount -= 1;
1189
1190 // Destroy if no longer used.
1191 if (ref->objcount == 0) {
1192 _PyChannelState *chan = NULL;
1193 _channels_remove_ref(channels, ref, prev, &chan);
1194 if (chan != NULL) {
1195 _channel_free(chan);
1196 }
1197 }
1198
1199done:
1200 PyThread_release_lock(channels->mutex);
1201}
1202
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001203static int64_t *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001204_channels_list_all(_channels *channels, int64_t *count)
1205{
1206 int64_t *cids = NULL;
1207 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1208 int64_t numopen = channels->numopen;
1209 if (numopen >= PY_SSIZE_T_MAX) {
1210 PyErr_SetString(PyExc_RuntimeError, "too many channels open");
1211 goto done;
1212 }
1213 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
1214 if (ids == NULL) {
1215 goto done;
1216 }
1217 _channelref *ref = channels->head;
1218 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
1219 ids[i] = ref->id;
1220 }
1221 *count = channels->numopen;
1222
1223 cids = ids;
1224done:
1225 PyThread_release_lock(channels->mutex);
1226 return cids;
1227}
1228
Eric Snow3ab01362018-05-17 10:27:09 -04001229/* support for closing non-empty channels */
1230
1231struct _channel_closing {
1232 struct _channelref *ref;
1233};
1234
1235static int
1236_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
1237 struct _channel *chan = ref->chan;
1238 if (chan == NULL) {
1239 // already closed
1240 return 0;
1241 }
1242 int res = -1;
1243 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1244 if (chan->closing != NULL) {
1245 PyErr_SetString(ChannelClosedError, "channel closed");
1246 goto done;
1247 }
1248 chan->closing = PyMem_NEW(struct _channel_closing, 1);
1249 if (chan->closing == NULL) {
1250 goto done;
1251 }
1252 chan->closing->ref = ref;
1253
1254 res = 0;
1255done:
1256 PyThread_release_lock(chan->mutex);
1257 return res;
1258}
1259
1260static void
1261_channel_clear_closing(struct _channel *chan) {
1262 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1263 if (chan->closing != NULL) {
1264 PyMem_Free(chan->closing);
1265 chan->closing = NULL;
1266 }
1267 PyThread_release_lock(chan->mutex);
1268}
1269
1270static void
1271_channel_finish_closing(struct _channel *chan) {
1272 struct _channel_closing *closing = chan->closing;
1273 if (closing == NULL) {
1274 return;
1275 }
1276 _channelref *ref = closing->ref;
1277 _channel_clear_closing(chan);
1278 // Do the things that would have been done in _channels_close().
1279 ref->chan = NULL;
1280 _channel_free(chan);
1281};
1282
Eric Snow7f8bfc92018-01-29 18:23:44 -07001283/* "high"-level channel-related functions */
1284
1285static int64_t
1286_channel_create(_channels *channels)
1287{
1288 _PyChannelState *chan = _channel_new();
1289 if (chan == NULL) {
1290 return -1;
1291 }
1292 int64_t id = _channels_add(channels, chan);
1293 if (id < 0) {
1294 _channel_free(chan);
1295 return -1;
1296 }
1297 return id;
1298}
1299
1300static int
1301_channel_destroy(_channels *channels, int64_t id)
1302{
1303 _PyChannelState *chan = NULL;
1304 if (_channels_remove(channels, id, &chan) != 0) {
1305 return -1;
1306 }
1307 if (chan != NULL) {
1308 _channel_free(chan);
1309 }
1310 return 0;
1311}
1312
1313static int
1314_channel_send(_channels *channels, int64_t id, PyObject *obj)
1315{
1316 PyInterpreterState *interp = _get_current();
1317 if (interp == NULL) {
1318 return -1;
1319 }
1320
1321 // Look up the channel.
1322 PyThread_type_lock mutex = NULL;
1323 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1324 if (chan == NULL) {
1325 return -1;
1326 }
1327 // Past this point we are responsible for releasing the mutex.
1328
Eric Snow3ab01362018-05-17 10:27:09 -04001329 if (chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001330 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow3ab01362018-05-17 10:27:09 -04001331 PyThread_release_lock(mutex);
1332 return -1;
1333 }
1334
Eric Snow7f8bfc92018-01-29 18:23:44 -07001335 // Convert the object to cross-interpreter data.
1336 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
1337 if (data == NULL) {
1338 PyThread_release_lock(mutex);
1339 return -1;
1340 }
1341 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
1342 PyThread_release_lock(mutex);
1343 return -1;
1344 }
1345
1346 // Add the data to the channel.
1347 int res = _channel_add(chan, interp->id, data);
1348 PyThread_release_lock(mutex);
1349 if (res != 0) {
1350 _PyCrossInterpreterData_Release(data);
1351 PyMem_Free(data);
1352 return -1;
1353 }
1354
1355 return 0;
1356}
1357
1358static PyObject *
1359_channel_recv(_channels *channels, int64_t id)
1360{
1361 PyInterpreterState *interp = _get_current();
1362 if (interp == NULL) {
1363 return NULL;
1364 }
1365
1366 // Look up the channel.
1367 PyThread_type_lock mutex = NULL;
1368 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1369 if (chan == NULL) {
1370 return NULL;
1371 }
1372 // Past this point we are responsible for releasing the mutex.
1373
1374 // Pop off the next item from the channel.
1375 _PyCrossInterpreterData *data = _channel_next(chan, interp->id);
1376 PyThread_release_lock(mutex);
1377 if (data == NULL) {
Eric Snow6d2cd902018-05-16 15:04:57 -04001378 if (!PyErr_Occurred()) {
Eric Snowab4a1982018-06-13 08:02:39 -06001379 PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001380 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001381 return NULL;
1382 }
1383
1384 // Convert the data back to an object.
1385 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
1386 if (obj == NULL) {
1387 return NULL;
1388 }
1389 _PyCrossInterpreterData_Release(data);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001390 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001391
1392 return obj;
1393}
1394
1395static int
1396_channel_drop(_channels *channels, int64_t id, int send, int recv)
1397{
1398 PyInterpreterState *interp = _get_current();
1399 if (interp == NULL) {
1400 return -1;
1401 }
1402
1403 // Look up the channel.
1404 PyThread_type_lock mutex = NULL;
1405 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1406 if (chan == NULL) {
1407 return -1;
1408 }
1409 // Past this point we are responsible for releasing the mutex.
1410
1411 // Close one or both of the two ends.
Eric Snow4e9da0d2018-02-02 21:49:49 -07001412 int res = _channel_close_interpreter(chan, interp->id, send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001413 PyThread_release_lock(mutex);
1414 return res;
1415}
1416
1417static int
Eric Snow3ab01362018-05-17 10:27:09 -04001418_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001419{
Eric Snow3ab01362018-05-17 10:27:09 -04001420 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001421}
1422
1423/* ChannelID class */
1424
Eric Snow7f8bfc92018-01-29 18:23:44 -07001425static PyTypeObject ChannelIDtype;
1426
1427typedef struct channelid {
1428 PyObject_HEAD
1429 int64_t id;
1430 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001431 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001432 _channels *channels;
1433} channelid;
1434
1435static channelid *
1436newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001437 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001438{
1439 channelid *self = PyObject_New(channelid, cls);
1440 if (self == NULL) {
1441 return NULL;
1442 }
1443 self->id = cid;
1444 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001445 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001446 self->channels = channels;
1447
1448 if (_channels_add_id_object(channels, cid) != 0) {
1449 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1450 PyErr_Clear();
1451 }
1452 else {
1453 Py_DECREF((PyObject *)self);
1454 return NULL;
1455 }
1456 }
1457
1458 return self;
1459}
1460
1461static _channels * _global_channels(void);
1462
1463static PyObject *
1464channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1465{
Eric Snow6d2cd902018-05-16 15:04:57 -04001466 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07001467 PyObject *id;
1468 int send = -1;
1469 int recv = -1;
1470 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001471 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001472 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04001473 "O|$pppp:ChannelID.__new__", kwlist,
1474 &id, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001475 return NULL;
1476
1477 // Coerce and check the ID.
1478 int64_t cid;
1479 if (PyObject_TypeCheck(id, &ChannelIDtype)) {
1480 cid = ((channelid *)id)->id;
1481 }
1482 else {
1483 cid = _coerce_id(id);
1484 if (cid < 0) {
1485 return NULL;
1486 }
1487 }
1488
1489 // Handle "send" and "recv".
1490 if (send == 0 && recv == 0) {
1491 PyErr_SetString(PyExc_ValueError,
1492 "'send' and 'recv' cannot both be False");
1493 return NULL;
1494 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001495
Eric Snow7f8bfc92018-01-29 18:23:44 -07001496 int end = 0;
1497 if (send == 1) {
1498 if (recv == 0 || recv == -1) {
1499 end = CHANNEL_SEND;
1500 }
1501 }
1502 else if (recv == 1) {
1503 end = CHANNEL_RECV;
1504 }
1505
Eric Snow6d2cd902018-05-16 15:04:57 -04001506 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
1507 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001508}
1509
1510static void
1511channelid_dealloc(PyObject *v)
1512{
1513 int64_t cid = ((channelid *)v)->id;
1514 _channels *channels = ((channelid *)v)->channels;
1515 Py_TYPE(v)->tp_free(v);
1516
1517 _channels_drop_id_object(channels, cid);
1518}
1519
1520static PyObject *
1521channelid_repr(PyObject *self)
1522{
1523 PyTypeObject *type = Py_TYPE(self);
1524 const char *name = _PyType_Name(type);
1525
1526 channelid *cid = (channelid *)self;
1527 const char *fmt;
1528 if (cid->end == CHANNEL_SEND) {
Eric Snowab4a1982018-06-13 08:02:39 -06001529 fmt = "%s(%" PRId64 ", send=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001530 }
1531 else if (cid->end == CHANNEL_RECV) {
Eric Snowab4a1982018-06-13 08:02:39 -06001532 fmt = "%s(%" PRId64 ", recv=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001533 }
1534 else {
Eric Snowab4a1982018-06-13 08:02:39 -06001535 fmt = "%s(%" PRId64 ")";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001536 }
1537 return PyUnicode_FromFormat(fmt, name, cid->id);
1538}
1539
Eric Snow6d2cd902018-05-16 15:04:57 -04001540static PyObject *
1541channelid_str(PyObject *self)
1542{
1543 channelid *cid = (channelid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06001544 return PyUnicode_FromFormat("%" PRId64 "", cid->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001545}
1546
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001547static PyObject *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001548channelid_int(PyObject *self)
1549{
1550 channelid *cid = (channelid *)self;
1551 return PyLong_FromLongLong(cid->id);
1552}
1553
1554static PyNumberMethods channelid_as_number = {
1555 0, /* nb_add */
1556 0, /* nb_subtract */
1557 0, /* nb_multiply */
1558 0, /* nb_remainder */
1559 0, /* nb_divmod */
1560 0, /* nb_power */
1561 0, /* nb_negative */
1562 0, /* nb_positive */
1563 0, /* nb_absolute */
1564 0, /* nb_bool */
1565 0, /* nb_invert */
1566 0, /* nb_lshift */
1567 0, /* nb_rshift */
1568 0, /* nb_and */
1569 0, /* nb_xor */
1570 0, /* nb_or */
1571 (unaryfunc)channelid_int, /* nb_int */
1572 0, /* nb_reserved */
1573 0, /* nb_float */
1574
1575 0, /* nb_inplace_add */
1576 0, /* nb_inplace_subtract */
1577 0, /* nb_inplace_multiply */
1578 0, /* nb_inplace_remainder */
1579 0, /* nb_inplace_power */
1580 0, /* nb_inplace_lshift */
1581 0, /* nb_inplace_rshift */
1582 0, /* nb_inplace_and */
1583 0, /* nb_inplace_xor */
1584 0, /* nb_inplace_or */
1585
1586 0, /* nb_floor_divide */
1587 0, /* nb_true_divide */
1588 0, /* nb_inplace_floor_divide */
1589 0, /* nb_inplace_true_divide */
1590
1591 (unaryfunc)channelid_int, /* nb_index */
1592};
1593
1594static Py_hash_t
1595channelid_hash(PyObject *self)
1596{
1597 channelid *cid = (channelid *)self;
1598 PyObject *id = PyLong_FromLongLong(cid->id);
1599 if (id == NULL) {
1600 return -1;
1601 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001602 Py_hash_t hash = PyObject_Hash(id);
1603 Py_DECREF(id);
1604 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001605}
1606
1607static PyObject *
1608channelid_richcompare(PyObject *self, PyObject *other, int op)
1609{
1610 if (op != Py_EQ && op != Py_NE) {
1611 Py_RETURN_NOTIMPLEMENTED;
1612 }
1613
1614 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1615 Py_RETURN_NOTIMPLEMENTED;
1616 }
1617
1618 channelid *cid = (channelid *)self;
1619 int equal;
1620 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1621 channelid *othercid = (channelid *)other;
1622 if (cid->end != othercid->end) {
1623 equal = 0;
1624 }
1625 else {
1626 equal = (cid->id == othercid->id);
1627 }
1628 }
1629 else {
1630 other = PyNumber_Long(other);
1631 if (other == NULL) {
1632 PyErr_Clear();
1633 Py_RETURN_NOTIMPLEMENTED;
1634 }
1635 int64_t othercid = PyLong_AsLongLong(other);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001636 Py_DECREF(other);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001637 if (othercid == -1 && PyErr_Occurred() != NULL) {
1638 return NULL;
1639 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001640 if (othercid < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001641 equal = 0;
1642 }
1643 else {
1644 equal = (cid->id == othercid);
1645 }
1646 }
1647
1648 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1649 Py_RETURN_TRUE;
1650 }
1651 Py_RETURN_FALSE;
1652}
1653
Eric Snowab4a1982018-06-13 08:02:39 -06001654static PyObject *
1655_channel_from_cid(PyObject *cid, int end)
1656{
1657 PyObject *highlevel = PyImport_ImportModule("interpreters");
1658 if (highlevel == NULL) {
1659 PyErr_Clear();
1660 highlevel = PyImport_ImportModule("test.support.interpreters");
1661 if (highlevel == NULL) {
1662 return NULL;
1663 }
1664 }
1665 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
1666 "SendChannel";
1667 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1668 Py_DECREF(highlevel);
1669 if (cls == NULL) {
1670 return NULL;
1671 }
1672 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1673 Py_DECREF(cls);
1674 if (chan == NULL) {
1675 return NULL;
1676 }
1677 return chan;
1678}
1679
Eric Snow7f8bfc92018-01-29 18:23:44 -07001680struct _channelid_xid {
1681 int64_t id;
1682 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001683 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001684};
1685
1686static PyObject *
1687_channelid_from_xid(_PyCrossInterpreterData *data)
1688{
1689 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001690 // Note that we do not preserve the "resolve" flag.
1691 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1692 _global_channels(), 0, 0);
1693 if (xid->end == 0) {
1694 return cid;
1695 }
1696 if (!xid->resolve) {
1697 return cid;
1698 }
1699
1700 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06001701 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04001702 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001703 PyErr_Clear();
1704 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04001705 }
1706 Py_DECREF(cid);
1707 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001708}
1709
1710static int
1711_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1712{
1713 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1714 if (xid == NULL) {
1715 return -1;
1716 }
1717 xid->id = ((channelid *)obj)->id;
1718 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001719 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001720
1721 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06001722 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001723 data->obj = obj;
1724 data->new_object = _channelid_from_xid;
1725 data->free = PyMem_Free;
1726 return 0;
1727}
1728
1729static PyObject *
1730channelid_end(PyObject *self, void *end)
1731{
1732 int force = 1;
1733 channelid *cid = (channelid *)self;
1734 if (end != NULL) {
1735 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001736 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001737 }
1738
1739 if (cid->end == CHANNEL_SEND) {
1740 return PyUnicode_InternFromString("send");
1741 }
1742 if (cid->end == CHANNEL_RECV) {
1743 return PyUnicode_InternFromString("recv");
1744 }
1745 return PyUnicode_InternFromString("both");
1746}
1747
1748static int _channelid_end_send = CHANNEL_SEND;
1749static int _channelid_end_recv = CHANNEL_RECV;
1750
1751static PyGetSetDef channelid_getsets[] = {
1752 {"end", (getter)channelid_end, NULL,
1753 PyDoc_STR("'send', 'recv', or 'both'")},
1754 {"send", (getter)channelid_end, NULL,
1755 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1756 {"recv", (getter)channelid_end, NULL,
1757 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1758 {NULL}
1759};
1760
1761PyDoc_STRVAR(channelid_doc,
1762"A channel ID identifies a channel and may be used as an int.");
1763
1764static PyTypeObject ChannelIDtype = {
1765 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1766 "_xxsubinterpreters.ChannelID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02001767 sizeof(channelid), /* tp_basicsize */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001768 0, /* tp_itemsize */
1769 (destructor)channelid_dealloc, /* tp_dealloc */
1770 0, /* tp_print */
1771 0, /* tp_getattr */
1772 0, /* tp_setattr */
1773 0, /* tp_as_async */
1774 (reprfunc)channelid_repr, /* tp_repr */
1775 &channelid_as_number, /* tp_as_number */
1776 0, /* tp_as_sequence */
1777 0, /* tp_as_mapping */
1778 channelid_hash, /* tp_hash */
1779 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001780 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001781 0, /* tp_getattro */
1782 0, /* tp_setattro */
1783 0, /* tp_as_buffer */
1784 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1785 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
1786 channelid_doc, /* tp_doc */
1787 0, /* tp_traverse */
1788 0, /* tp_clear */
1789 channelid_richcompare, /* tp_richcompare */
1790 0, /* tp_weaklistoffset */
1791 0, /* tp_iter */
1792 0, /* tp_iternext */
1793 0, /* tp_methods */
1794 0, /* tp_members */
1795 channelid_getsets, /* tp_getset */
1796 0, /* tp_base */
1797 0, /* tp_dict */
1798 0, /* tp_descr_get */
1799 0, /* tp_descr_set */
1800 0, /* tp_dictoffset */
1801 0, /* tp_init */
1802 0, /* tp_alloc */
1803 // Note that we do not set tp_new to channelid_new. Instead we
1804 // set it to NULL, meaning it cannot be instantiated from Python
1805 // code. We do this because there is a strong relationship between
1806 // channel IDs and the channel lifecycle, so this limitation avoids
1807 // related complications.
1808 NULL, /* tp_new */
1809};
1810
Eric Snow4e9da0d2018-02-02 21:49:49 -07001811
1812/* interpreter-specific code ************************************************/
1813
1814static PyObject * RunFailedError = NULL;
1815
1816static int
1817interp_exceptions_init(PyObject *ns)
1818{
1819 // XXX Move the exceptions into per-module memory?
1820
1821 if (RunFailedError == NULL) {
1822 // An uncaught exception came out of interp_run_string().
1823 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1824 PyExc_RuntimeError, NULL);
1825 if (RunFailedError == NULL) {
1826 return -1;
1827 }
1828 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1829 return -1;
1830 }
1831 }
1832
1833 return 0;
1834}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001835
Eric Snow7f8bfc92018-01-29 18:23:44 -07001836static int
1837_is_running(PyInterpreterState *interp)
1838{
1839 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1840 if (PyThreadState_Next(tstate) != NULL) {
1841 PyErr_SetString(PyExc_RuntimeError,
1842 "interpreter has more than one thread");
1843 return -1;
1844 }
1845 PyFrameObject *frame = tstate->frame;
1846 if (frame == NULL) {
1847 if (PyErr_Occurred() != NULL) {
1848 return -1;
1849 }
1850 return 0;
1851 }
1852 return (int)(frame->f_executing);
1853}
1854
1855static int
1856_ensure_not_running(PyInterpreterState *interp)
1857{
1858 int is_running = _is_running(interp);
1859 if (is_running < 0) {
1860 return -1;
1861 }
1862 if (is_running) {
1863 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1864 return -1;
1865 }
1866 return 0;
1867}
1868
1869static int
1870_run_script(PyInterpreterState *interp, const char *codestr,
Eric Snow4e9da0d2018-02-02 21:49:49 -07001871 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001872{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001873 PyObject *exctype = NULL;
1874 PyObject *excval = NULL;
1875 PyObject *tb = NULL;
1876
Eric Snow7f8bfc92018-01-29 18:23:44 -07001877 PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
1878 if (main_mod == NULL) {
1879 goto error;
1880 }
1881 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1882 Py_DECREF(main_mod);
1883 if (ns == NULL) {
1884 goto error;
1885 }
1886 Py_INCREF(ns);
1887
1888 // Apply the cross-interpreter data.
1889 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001890 if (_sharedns_apply(shared, ns) != 0) {
1891 Py_DECREF(ns);
1892 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001893 }
1894 }
1895
1896 // Run the string (see PyRun_SimpleStringFlags).
1897 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1898 Py_DECREF(ns);
1899 if (result == NULL) {
1900 goto error;
1901 }
1902 else {
1903 Py_DECREF(result); // We throw away the result.
1904 }
1905
Eric Snow4e9da0d2018-02-02 21:49:49 -07001906 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001907 return 0;
1908
1909error:
Eric Snow4e9da0d2018-02-02 21:49:49 -07001910 PyErr_Fetch(&exctype, &excval, &tb);
1911
1912 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1913 Py_XDECREF(exctype);
1914 Py_XDECREF(excval);
1915 Py_XDECREF(tb);
1916 if (sharedexc == NULL) {
1917 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1918 PyErr_Clear();
1919 sharedexc = NULL;
1920 }
1921 else {
1922 assert(!PyErr_Occurred());
1923 }
1924 *exc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001925 return -1;
1926}
1927
1928static int
1929_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1930 PyObject *shareables)
1931{
1932 if (_ensure_not_running(interp) < 0) {
1933 return -1;
1934 }
1935
Eric Snow4e9da0d2018-02-02 21:49:49 -07001936 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001937 if (shared == NULL && PyErr_Occurred()) {
1938 return -1;
1939 }
1940
1941 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001942 PyThreadState *save_tstate = NULL;
Victor Stinnercaba55b2018-08-03 15:33:52 +02001943 if (interp != _PyInterpreterState_Get()) {
Eric Snowf53d9f22018-02-20 16:30:17 -07001944 // XXX Using the "head" thread isn't strictly correct.
1945 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1946 // XXX Possible GILState issues?
1947 save_tstate = PyThreadState_Swap(tstate);
1948 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001949
1950 // Run the script.
1951 _sharedexception *exc = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001952 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001953
1954 // Switch back.
1955 if (save_tstate != NULL) {
1956 PyThreadState_Swap(save_tstate);
1957 }
1958
1959 // Propagate any exception out to the caller.
1960 if (exc != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001961 _sharedexception_apply(exc, RunFailedError);
1962 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001963 }
1964 else if (result != 0) {
1965 // We were unable to allocate a shared exception.
1966 PyErr_NoMemory();
1967 }
1968
1969 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001970 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001971 }
1972
1973 return result;
1974}
1975
Eric Snow4c6955e2018-02-16 18:53:40 -07001976/* InterpreterID class */
1977
1978static PyTypeObject InterpreterIDtype;
1979
1980typedef struct interpid {
1981 PyObject_HEAD
1982 int64_t id;
1983} interpid;
1984
1985static interpid *
1986newinterpid(PyTypeObject *cls, int64_t id, int force)
1987{
1988 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
1989 if (interp == NULL) {
1990 if (force) {
1991 PyErr_Clear();
1992 }
1993 else {
1994 return NULL;
1995 }
1996 }
1997
1998 interpid *self = PyObject_New(interpid, cls);
1999 if (self == NULL) {
2000 return NULL;
2001 }
2002 self->id = id;
2003
2004 if (interp != NULL) {
2005 _PyInterpreterState_IDIncref(interp);
2006 }
2007 return self;
2008}
2009
2010static PyObject *
2011interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
2012{
2013 static char *kwlist[] = {"id", "force", NULL};
2014 PyObject *idobj;
2015 int force = 0;
2016 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2017 "O|$p:InterpreterID.__init__", kwlist,
2018 &idobj, &force)) {
2019 return NULL;
2020 }
2021
2022 // Coerce and check the ID.
2023 int64_t id;
2024 if (PyObject_TypeCheck(idobj, &InterpreterIDtype)) {
2025 id = ((interpid *)idobj)->id;
2026 }
2027 else {
2028 id = _coerce_id(idobj);
2029 if (id < 0) {
2030 return NULL;
2031 }
2032 }
2033
2034 return (PyObject *)newinterpid(cls, id, force);
2035}
2036
2037static void
2038interpid_dealloc(PyObject *v)
2039{
2040 int64_t id = ((interpid *)v)->id;
2041 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
2042 if (interp != NULL) {
2043 _PyInterpreterState_IDDecref(interp);
2044 }
2045 else {
2046 // already deleted
2047 PyErr_Clear();
2048 }
2049 Py_TYPE(v)->tp_free(v);
2050}
2051
2052static PyObject *
2053interpid_repr(PyObject *self)
2054{
2055 PyTypeObject *type = Py_TYPE(self);
2056 const char *name = _PyType_Name(type);
2057 interpid *id = (interpid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06002058 return PyUnicode_FromFormat("%s(%" PRId64 ")", name, id->id);
Eric Snow4c6955e2018-02-16 18:53:40 -07002059}
2060
Eric Snow6d2cd902018-05-16 15:04:57 -04002061static PyObject *
2062interpid_str(PyObject *self)
2063{
2064 interpid *id = (interpid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06002065 return PyUnicode_FromFormat("%" PRId64 "", id->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04002066}
2067
Eric Snow4c6955e2018-02-16 18:53:40 -07002068PyObject *
2069interpid_int(PyObject *self)
2070{
2071 interpid *id = (interpid *)self;
2072 return PyLong_FromLongLong(id->id);
2073}
2074
2075static PyNumberMethods interpid_as_number = {
2076 0, /* nb_add */
2077 0, /* nb_subtract */
2078 0, /* nb_multiply */
2079 0, /* nb_remainder */
2080 0, /* nb_divmod */
2081 0, /* nb_power */
2082 0, /* nb_negative */
2083 0, /* nb_positive */
2084 0, /* nb_absolute */
2085 0, /* nb_bool */
2086 0, /* nb_invert */
2087 0, /* nb_lshift */
2088 0, /* nb_rshift */
2089 0, /* nb_and */
2090 0, /* nb_xor */
2091 0, /* nb_or */
2092 (unaryfunc)interpid_int, /* nb_int */
2093 0, /* nb_reserved */
2094 0, /* nb_float */
2095
2096 0, /* nb_inplace_add */
2097 0, /* nb_inplace_subtract */
2098 0, /* nb_inplace_multiply */
2099 0, /* nb_inplace_remainder */
2100 0, /* nb_inplace_power */
2101 0, /* nb_inplace_lshift */
2102 0, /* nb_inplace_rshift */
2103 0, /* nb_inplace_and */
2104 0, /* nb_inplace_xor */
2105 0, /* nb_inplace_or */
2106
2107 0, /* nb_floor_divide */
2108 0, /* nb_true_divide */
2109 0, /* nb_inplace_floor_divide */
2110 0, /* nb_inplace_true_divide */
2111
2112 (unaryfunc)interpid_int, /* nb_index */
2113};
2114
2115static Py_hash_t
2116interpid_hash(PyObject *self)
2117{
2118 interpid *id = (interpid *)self;
2119 PyObject *obj = PyLong_FromLongLong(id->id);
2120 if (obj == NULL) {
2121 return -1;
2122 }
2123 Py_hash_t hash = PyObject_Hash(obj);
2124 Py_DECREF(obj);
2125 return hash;
2126}
2127
2128static PyObject *
2129interpid_richcompare(PyObject *self, PyObject *other, int op)
2130{
2131 if (op != Py_EQ && op != Py_NE) {
2132 Py_RETURN_NOTIMPLEMENTED;
2133 }
2134
2135 if (!PyObject_TypeCheck(self, &InterpreterIDtype)) {
2136 Py_RETURN_NOTIMPLEMENTED;
2137 }
2138
2139 interpid *id = (interpid *)self;
2140 int equal;
2141 if (PyObject_TypeCheck(other, &InterpreterIDtype)) {
2142 interpid *otherid = (interpid *)other;
2143 equal = (id->id == otherid->id);
2144 }
2145 else {
2146 other = PyNumber_Long(other);
2147 if (other == NULL) {
2148 PyErr_Clear();
2149 Py_RETURN_NOTIMPLEMENTED;
2150 }
2151 int64_t otherid = PyLong_AsLongLong(other);
2152 Py_DECREF(other);
2153 if (otherid == -1 && PyErr_Occurred() != NULL) {
2154 return NULL;
2155 }
2156 if (otherid < 0) {
2157 equal = 0;
2158 }
2159 else {
2160 equal = (id->id == otherid);
2161 }
2162 }
2163
2164 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
2165 Py_RETURN_TRUE;
2166 }
2167 Py_RETURN_FALSE;
2168}
2169
2170PyDoc_STRVAR(interpid_doc,
2171"A interpreter ID identifies a interpreter and may be used as an int.");
2172
2173static PyTypeObject InterpreterIDtype = {
2174 PyVarObject_HEAD_INIT(&PyType_Type, 0)
2175 "interpreters.InterpreterID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02002176 sizeof(interpid), /* tp_basicsize */
Eric Snow4c6955e2018-02-16 18:53:40 -07002177 0, /* tp_itemsize */
2178 (destructor)interpid_dealloc, /* tp_dealloc */
2179 0, /* tp_print */
2180 0, /* tp_getattr */
2181 0, /* tp_setattr */
2182 0, /* tp_as_async */
2183 (reprfunc)interpid_repr, /* tp_repr */
2184 &interpid_as_number, /* tp_as_number */
2185 0, /* tp_as_sequence */
2186 0, /* tp_as_mapping */
2187 interpid_hash, /* tp_hash */
2188 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04002189 (reprfunc)interpid_str, /* tp_str */
Eric Snow4c6955e2018-02-16 18:53:40 -07002190 0, /* tp_getattro */
2191 0, /* tp_setattro */
2192 0, /* tp_as_buffer */
2193 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
2194 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
2195 interpid_doc, /* tp_doc */
2196 0, /* tp_traverse */
2197 0, /* tp_clear */
2198 interpid_richcompare, /* tp_richcompare */
2199 0, /* tp_weaklistoffset */
2200 0, /* tp_iter */
2201 0, /* tp_iternext */
2202 0, /* tp_methods */
2203 0, /* tp_members */
2204 0, /* tp_getset */
2205 0, /* tp_base */
2206 0, /* tp_dict */
2207 0, /* tp_descr_get */
2208 0, /* tp_descr_set */
2209 0, /* tp_dictoffset */
2210 0, /* tp_init */
2211 0, /* tp_alloc */
2212 interpid_new, /* tp_new */
2213};
2214
2215static PyObject *
2216_get_id(PyInterpreterState *interp)
2217{
2218 PY_INT64_T id = PyInterpreterState_GetID(interp);
2219 if (id < 0) {
2220 return NULL;
2221 }
2222 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
2223}
2224
2225static PyInterpreterState *
2226_look_up(PyObject *requested_id)
2227{
2228 int64_t id;
2229 if (PyObject_TypeCheck(requested_id, &InterpreterIDtype)) {
2230 id = ((interpid *)requested_id)->id;
2231 }
2232 else {
2233 id = PyLong_AsLongLong(requested_id);
2234 if (id == -1 && PyErr_Occurred() != NULL) {
2235 return NULL;
2236 }
2237 assert(id <= INT64_MAX);
2238 }
2239 return _PyInterpreterState_LookUpID(id);
2240}
2241
Eric Snow7f8bfc92018-01-29 18:23:44 -07002242
2243/* module level code ********************************************************/
2244
2245/* globals is the process-global state for the module. It holds all
2246 the data that we need to share between interpreters, so it cannot
2247 hold PyObject values. */
2248static struct globals {
2249 _channels channels;
2250} _globals = {{0}};
2251
2252static int
2253_init_globals(void)
2254{
2255 if (_channels_init(&_globals.channels) != 0) {
2256 return -1;
2257 }
2258 return 0;
2259}
2260
2261static _channels *
2262_global_channels(void) {
2263 return &_globals.channels;
2264}
2265
2266static PyObject *
2267interp_create(PyObject *self, PyObject *args)
2268{
2269 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
2270 return NULL;
2271 }
2272
2273 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002274 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2275 // XXX Possible GILState issues?
2276 PyThreadState *tstate = Py_NewInterpreter();
Eric Snow7f8bfc92018-01-29 18:23:44 -07002277 PyThreadState_Swap(save_tstate);
2278 if (tstate == NULL) {
2279 /* Since no new thread state was created, there is no exception to
2280 propagate; raise a fresh one after swapping in the old thread
2281 state. */
2282 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2283 return NULL;
2284 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002285 if (_PyInterpreterState_IDInitref(tstate->interp) != 0) {
2286 goto error;
2287 };
Eric Snow7f8bfc92018-01-29 18:23:44 -07002288 return _get_id(tstate->interp);
Eric Snow4c6955e2018-02-16 18:53:40 -07002289
2290error:
Eric Snowf53d9f22018-02-20 16:30:17 -07002291 // XXX Possible GILState issues?
Eric Snow4c6955e2018-02-16 18:53:40 -07002292 save_tstate = PyThreadState_Swap(tstate);
2293 Py_EndInterpreter(tstate);
2294 PyThreadState_Swap(save_tstate);
2295 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002296}
2297
2298PyDoc_STRVAR(create_doc,
2299"create() -> ID\n\
2300\n\
2301Create a new interpreter and return a unique generated ID.");
2302
2303
2304static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002305interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002306{
Eric Snow6d2cd902018-05-16 15:04:57 -04002307 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002308 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002309 // XXX Use "L" for id?
2310 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2311 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002312 return NULL;
2313 }
2314 if (!PyLong_Check(id)) {
2315 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2316 return NULL;
2317 }
2318
2319 // Look up the interpreter.
2320 PyInterpreterState *interp = _look_up(id);
2321 if (interp == NULL) {
2322 return NULL;
2323 }
2324
2325 // Ensure we don't try to destroy the current interpreter.
2326 PyInterpreterState *current = _get_current();
2327 if (current == NULL) {
2328 return NULL;
2329 }
2330 if (interp == current) {
2331 PyErr_SetString(PyExc_RuntimeError,
2332 "cannot destroy the current interpreter");
2333 return NULL;
2334 }
2335
2336 // Ensure the interpreter isn't running.
2337 /* XXX We *could* support destroying a running interpreter but
2338 aren't going to worry about it for now. */
2339 if (_ensure_not_running(interp) < 0) {
2340 return NULL;
2341 }
2342
2343 // Destroy the interpreter.
2344 //PyInterpreterState_Delete(interp);
Eric Snowf53d9f22018-02-20 16:30:17 -07002345 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2346 // XXX Possible GILState issues?
2347 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002348 Py_EndInterpreter(tstate);
2349 PyThreadState_Swap(save_tstate);
2350
2351 Py_RETURN_NONE;
2352}
2353
2354PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002355"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002356\n\
2357Destroy the identified interpreter.\n\
2358\n\
2359Attempting to destroy the current interpreter results in a RuntimeError.\n\
2360So does an unrecognized ID.");
2361
2362
2363static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302364interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002365{
2366 PyObject *ids, *id;
2367 PyInterpreterState *interp;
2368
2369 ids = PyList_New(0);
2370 if (ids == NULL) {
2371 return NULL;
2372 }
2373
2374 interp = PyInterpreterState_Head();
2375 while (interp != NULL) {
2376 id = _get_id(interp);
2377 if (id == NULL) {
2378 Py_DECREF(ids);
2379 return NULL;
2380 }
2381 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002382 int res = PyList_Insert(ids, 0, id);
2383 Py_DECREF(id);
2384 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002385 Py_DECREF(ids);
2386 return NULL;
2387 }
2388
2389 interp = PyInterpreterState_Next(interp);
2390 }
2391
2392 return ids;
2393}
2394
2395PyDoc_STRVAR(list_all_doc,
2396"list_all() -> [ID]\n\
2397\n\
2398Return a list containing the ID of every existing interpreter.");
2399
2400
2401static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302402interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002403{
2404 PyInterpreterState *interp =_get_current();
2405 if (interp == NULL) {
2406 return NULL;
2407 }
2408 return _get_id(interp);
2409}
2410
2411PyDoc_STRVAR(get_current_doc,
2412"get_current() -> ID\n\
2413\n\
2414Return the ID of current interpreter.");
2415
2416
2417static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302418interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002419{
2420 // Currently, 0 is always the main interpreter.
Eric Snow6d2cd902018-05-16 15:04:57 -04002421 PY_INT64_T id = 0;
2422 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002423}
2424
2425PyDoc_STRVAR(get_main_doc,
2426"get_main() -> ID\n\
2427\n\
2428Return the ID of main interpreter.");
2429
2430
2431static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002432interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002433{
Eric Snow6d2cd902018-05-16 15:04:57 -04002434 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002435 PyObject *id, *code;
2436 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002437 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2438 "OU|O:run_string", kwlist,
2439 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002440 return NULL;
2441 }
2442 if (!PyLong_Check(id)) {
2443 PyErr_SetString(PyExc_TypeError, "first arg (ID) must be an int");
2444 return NULL;
2445 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002446
2447 // Look up the interpreter.
2448 PyInterpreterState *interp = _look_up(id);
2449 if (interp == NULL) {
2450 return NULL;
2451 }
2452
2453 // Extract code.
2454 Py_ssize_t size;
2455 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2456 if (codestr == NULL) {
2457 return NULL;
2458 }
2459 if (strlen(codestr) != (size_t)size) {
2460 PyErr_SetString(PyExc_ValueError,
2461 "source code string cannot contain null bytes");
2462 return NULL;
2463 }
2464
2465 // Run the code in the interpreter.
2466 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2467 return NULL;
2468 }
2469 Py_RETURN_NONE;
2470}
2471
2472PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002473"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002474\n\
2475Execute the provided string in the identified interpreter.\n\
2476\n\
2477See PyRun_SimpleStrings.");
2478
2479
2480static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002481object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002482{
Eric Snow6d2cd902018-05-16 15:04:57 -04002483 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002484 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002485 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2486 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002487 return NULL;
2488 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002489
Eric Snow7f8bfc92018-01-29 18:23:44 -07002490 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2491 Py_RETURN_TRUE;
2492 }
2493 PyErr_Clear();
2494 Py_RETURN_FALSE;
2495}
2496
2497PyDoc_STRVAR(is_shareable_doc,
2498"is_shareable(obj) -> bool\n\
2499\n\
2500Return True if the object's data may be shared between interpreters and\n\
2501False otherwise.");
2502
2503
2504static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002505interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002506{
Eric Snow6d2cd902018-05-16 15:04:57 -04002507 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002508 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002509 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2510 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002511 return NULL;
2512 }
2513 if (!PyLong_Check(id)) {
2514 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2515 return NULL;
2516 }
2517
2518 PyInterpreterState *interp = _look_up(id);
2519 if (interp == NULL) {
2520 return NULL;
2521 }
2522 int is_running = _is_running(interp);
2523 if (is_running < 0) {
2524 return NULL;
2525 }
2526 if (is_running) {
2527 Py_RETURN_TRUE;
2528 }
2529 Py_RETURN_FALSE;
2530}
2531
2532PyDoc_STRVAR(is_running_doc,
2533"is_running(id) -> bool\n\
2534\n\
2535Return whether or not the identified interpreter is running.");
2536
2537static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302538channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002539{
2540 int64_t cid = _channel_create(&_globals.channels);
2541 if (cid < 0) {
2542 return NULL;
2543 }
2544 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002545 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002546 if (id == NULL) {
2547 if (_channel_destroy(&_globals.channels, cid) != 0) {
2548 // XXX issue a warning?
2549 }
2550 return NULL;
2551 }
2552 assert(((channelid *)id)->channels != NULL);
2553 return id;
2554}
2555
2556PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002557"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002558\n\
2559Create a new cross-interpreter channel and return a unique generated ID.");
2560
2561static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002562channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002563{
Eric Snow6d2cd902018-05-16 15:04:57 -04002564 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002565 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002566 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2567 "O:channel_destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002568 return NULL;
2569 }
2570 int64_t cid = _coerce_id(id);
2571 if (cid < 0) {
2572 return NULL;
2573 }
2574
2575 if (_channel_destroy(&_globals.channels, cid) != 0) {
2576 return NULL;
2577 }
2578 Py_RETURN_NONE;
2579}
2580
2581PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002582"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002583\n\
2584Close and finalize the channel. Afterward attempts to use the channel\n\
2585will behave as though it never existed.");
2586
2587static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302588channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002589{
2590 int64_t count = 0;
2591 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2592 if (cids == NULL) {
2593 if (count == 0) {
2594 return PyList_New(0);
2595 }
2596 return NULL;
2597 }
2598 PyObject *ids = PyList_New((Py_ssize_t)count);
2599 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002600 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002601 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002602 int64_t *cur = cids;
2603 for (int64_t i=0; i < count; cur++, i++) {
2604 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002605 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002606 if (id == NULL) {
2607 Py_DECREF(ids);
2608 ids = NULL;
2609 break;
2610 }
2611 PyList_SET_ITEM(ids, i, id);
2612 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002613
2614finally:
2615 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002616 return ids;
2617}
2618
2619PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002620"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002621\n\
2622Return the list of all IDs for active channels.");
2623
2624static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002625channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002626{
Eric Snow6d2cd902018-05-16 15:04:57 -04002627 static char *kwlist[] = {"cid", "obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002628 PyObject *id;
2629 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002630 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2631 "OO:channel_send", kwlist, &id, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002632 return NULL;
2633 }
2634 int64_t cid = _coerce_id(id);
2635 if (cid < 0) {
2636 return NULL;
2637 }
2638
2639 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2640 return NULL;
2641 }
2642 Py_RETURN_NONE;
2643}
2644
2645PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002646"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002647\n\
2648Add the object's data to the channel's queue.");
2649
2650static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002651channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002652{
Eric Snow6d2cd902018-05-16 15:04:57 -04002653 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002654 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002655 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2656 "O:channel_recv", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002657 return NULL;
2658 }
2659 int64_t cid = _coerce_id(id);
2660 if (cid < 0) {
2661 return NULL;
2662 }
2663
2664 return _channel_recv(&_globals.channels, cid);
2665}
2666
2667PyDoc_STRVAR(channel_recv_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002668"channel_recv(cid) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002669\n\
2670Return a new object from the data at the from of the channel's queue.");
2671
2672static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002673channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002674{
Eric Snow6d2cd902018-05-16 15:04:57 -04002675 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
2676 PyObject *id;
2677 int send = 0;
2678 int recv = 0;
2679 int force = 0;
2680 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2681 "O|$ppp:channel_close", kwlist,
2682 &id, &send, &recv, &force)) {
2683 return NULL;
2684 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002685 int64_t cid = _coerce_id(id);
2686 if (cid < 0) {
2687 return NULL;
2688 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002689
Eric Snow3ab01362018-05-17 10:27:09 -04002690 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002691 return NULL;
2692 }
2693 Py_RETURN_NONE;
2694}
2695
2696PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002697"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002698\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002699Close the channel for all interpreters.\n\
2700\n\
2701If the channel is empty then the keyword args are ignored and both\n\
2702ends are immediately closed. Otherwise, if 'force' is True then\n\
2703all queued items are released and both ends are immediately\n\
2704closed.\n\
2705\n\
2706If the channel is not empty *and* 'force' is False then following\n\
2707happens:\n\
2708\n\
2709 * recv is True (regardless of send):\n\
2710 - raise ChannelNotEmptyError\n\
2711 * recv is None and send is None:\n\
2712 - raise ChannelNotEmptyError\n\
2713 * send is True and recv is not True:\n\
2714 - fully close the 'send' end\n\
2715 - close the 'recv' end to interpreters not already receiving\n\
2716 - fully close it once empty\n\
2717\n\
2718Closing an already closed channel results in a ChannelClosedError.\n\
2719\n\
2720Once the channel's ID has no more ref counts in any interpreter\n\
2721the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002722
2723static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002724channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002725{
2726 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002727 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002728 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002729 int send = 0;
2730 int recv = 0;
2731 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002732 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04002733 "O|$ppp:channel_release", kwlist,
2734 &id, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002735 return NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002736 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002737 int64_t cid = _coerce_id(id);
2738 if (cid < 0) {
2739 return NULL;
2740 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002741 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002742 send = 1;
2743 recv = 1;
2744 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002745
2746 // XXX Handle force is True.
2747 // XXX Fix implicit release.
2748
Eric Snow7f8bfc92018-01-29 18:23:44 -07002749 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2750 return NULL;
2751 }
2752 Py_RETURN_NONE;
2753}
2754
Eric Snow6d2cd902018-05-16 15:04:57 -04002755PyDoc_STRVAR(channel_release_doc,
2756"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002757\n\
2758Close the channel for the current interpreter. 'send' and 'recv'\n\
2759(bool) may be used to indicate the ends to close. By default both\n\
2760ends are closed. Closing an already closed end is a noop.");
2761
2762static PyObject *
2763channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2764{
2765 return channelid_new(&ChannelIDtype, args, kwds);
2766}
2767
2768static PyMethodDef module_functions[] = {
2769 {"create", (PyCFunction)interp_create,
2770 METH_VARARGS, create_doc},
2771 {"destroy", (PyCFunction)interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002772 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302773 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002774 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302775 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002776 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302777 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002778 METH_NOARGS, get_main_doc},
2779 {"is_running", (PyCFunction)interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002780 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002781 {"run_string", (PyCFunction)interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002782 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002783
2784 {"is_shareable", (PyCFunction)object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002785 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002786
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302787 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002788 METH_NOARGS, channel_create_doc},
2789 {"channel_destroy", (PyCFunction)channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002790 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302791 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002792 METH_NOARGS, channel_list_all_doc},
2793 {"channel_send", (PyCFunction)channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002794 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002795 {"channel_recv", (PyCFunction)channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002796 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
2797 {"channel_close", (PyCFunction)channel_close,
2798 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
2799 {"channel_release", (PyCFunction)channel_release,
2800 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002801 {"_channel_id", (PyCFunction)channel__channel_id,
2802 METH_VARARGS | METH_KEYWORDS, NULL},
2803
2804 {NULL, NULL} /* sentinel */
2805};
2806
2807
2808/* initialization function */
2809
2810PyDoc_STRVAR(module_doc,
2811"This module provides primitive operations to manage Python interpreters.\n\
2812The 'interpreters' module provides a more convenient interface.");
2813
2814static struct PyModuleDef interpretersmodule = {
2815 PyModuleDef_HEAD_INIT,
2816 "_xxsubinterpreters", /* m_name */
2817 module_doc, /* m_doc */
2818 -1, /* m_size */
2819 module_functions, /* m_methods */
2820 NULL, /* m_slots */
2821 NULL, /* m_traverse */
2822 NULL, /* m_clear */
2823 NULL /* m_free */
2824};
2825
2826
2827PyMODINIT_FUNC
2828PyInit__xxsubinterpreters(void)
2829{
2830 if (_init_globals() != 0) {
2831 return NULL;
2832 }
2833
2834 /* Initialize types */
2835 ChannelIDtype.tp_base = &PyLong_Type;
2836 if (PyType_Ready(&ChannelIDtype) != 0) {
2837 return NULL;
2838 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002839 InterpreterIDtype.tp_base = &PyLong_Type;
2840 if (PyType_Ready(&InterpreterIDtype) != 0) {
2841 return NULL;
2842 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002843
2844 /* Create the module */
2845 PyObject *module = PyModule_Create(&interpretersmodule);
2846 if (module == NULL) {
2847 return NULL;
2848 }
2849
2850 /* Add exception types */
2851 PyObject *ns = PyModule_GetDict(module); // borrowed
2852 if (interp_exceptions_init(ns) != 0) {
2853 return NULL;
2854 }
2855 if (channel_exceptions_init(ns) != 0) {
2856 return NULL;
2857 }
2858
2859 /* Add other types */
2860 Py_INCREF(&ChannelIDtype);
2861 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2862 return NULL;
2863 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002864 Py_INCREF(&InterpreterIDtype);
2865 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&InterpreterIDtype) != 0) {
2866 return NULL;
2867 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002868
2869 if (_PyCrossInterpreterData_Register_Class(&ChannelIDtype, _channelid_shared)) {
2870 return NULL;
2871 }
2872
2873 return module;
2874}