• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* InterpreterID object */
2 
3 #include "Python.h"
4 #include "internal/pycore_pystate.h"
5 #include "interpreteridobject.h"
6 
7 
8 typedef struct interpid {
9     PyObject_HEAD
10     int64_t id;
11 } interpid;
12 
13 static interpid *
newinterpid(PyTypeObject * cls,int64_t id,int force)14 newinterpid(PyTypeObject *cls, int64_t id, int force)
15 {
16     PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
17     if (interp == NULL) {
18         if (force) {
19             PyErr_Clear();
20         }
21         else {
22             return NULL;
23         }
24     }
25 
26     interpid *self = PyObject_New(interpid, cls);
27     if (self == NULL) {
28         return NULL;
29     }
30     self->id = id;
31 
32     if (interp != NULL) {
33         _PyInterpreterState_IDIncref(interp);
34     }
35     return self;
36 }
37 
38 static int
interp_id_converter(PyObject * arg,void * ptr)39 interp_id_converter(PyObject *arg, void *ptr)
40 {
41     int64_t id;
42     if (PyObject_TypeCheck(arg, &_PyInterpreterID_Type)) {
43         id = ((interpid *)arg)->id;
44     }
45     else if (PyIndex_Check(arg)) {
46         id = PyLong_AsLongLong(arg);
47         if (id == -1 && PyErr_Occurred()) {
48             return 0;
49         }
50         if (id < 0) {
51             PyErr_Format(PyExc_ValueError,
52                          "interpreter ID must be a non-negative int, got %R", arg);
53             return 0;
54         }
55     }
56     else {
57         PyErr_Format(PyExc_TypeError,
58                      "interpreter ID must be an int, got %.100s",
59                      arg->ob_type->tp_name);
60         return 0;
61     }
62     *(int64_t *)ptr = id;
63     return 1;
64 }
65 
66 static PyObject *
interpid_new(PyTypeObject * cls,PyObject * args,PyObject * kwds)67 interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
68 {
69     static char *kwlist[] = {"id", "force", NULL};
70     int64_t id;
71     int force = 0;
72     if (!PyArg_ParseTupleAndKeywords(args, kwds,
73                                      "O&|$p:InterpreterID.__init__", kwlist,
74                                      interp_id_converter, &id, &force)) {
75         return NULL;
76     }
77 
78     return (PyObject *)newinterpid(cls, id, force);
79 }
80 
81 static void
interpid_dealloc(PyObject * v)82 interpid_dealloc(PyObject *v)
83 {
84     int64_t id = ((interpid *)v)->id;
85     PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
86     if (interp != NULL) {
87         _PyInterpreterState_IDDecref(interp);
88     }
89     else {
90         // already deleted
91         PyErr_Clear();
92     }
93     Py_TYPE(v)->tp_free(v);
94 }
95 
96 static PyObject *
interpid_repr(PyObject * self)97 interpid_repr(PyObject *self)
98 {
99     PyTypeObject *type = Py_TYPE(self);
100     const char *name = _PyType_Name(type);
101     interpid *id = (interpid *)self;
102     return PyUnicode_FromFormat("%s(%" PRId64 ")", name, id->id);
103 }
104 
105 static PyObject *
interpid_str(PyObject * self)106 interpid_str(PyObject *self)
107 {
108     interpid *id = (interpid *)self;
109     return PyUnicode_FromFormat("%" PRId64 "", id->id);
110 }
111 
112 static PyObject *
interpid_int(PyObject * self)113 interpid_int(PyObject *self)
114 {
115     interpid *id = (interpid *)self;
116     return PyLong_FromLongLong(id->id);
117 }
118 
119 static PyNumberMethods interpid_as_number = {
120      0,                       /* nb_add */
121      0,                       /* nb_subtract */
122      0,                       /* nb_multiply */
123      0,                       /* nb_remainder */
124      0,                       /* nb_divmod */
125      0,                       /* nb_power */
126      0,                       /* nb_negative */
127      0,                       /* nb_positive */
128      0,                       /* nb_absolute */
129      0,                       /* nb_bool */
130      0,                       /* nb_invert */
131      0,                       /* nb_lshift */
132      0,                       /* nb_rshift */
133      0,                       /* nb_and */
134      0,                       /* nb_xor */
135      0,                       /* nb_or */
136      (unaryfunc)interpid_int, /* nb_int */
137      0,                       /* nb_reserved */
138      0,                       /* nb_float */
139 
140      0,                       /* nb_inplace_add */
141      0,                       /* nb_inplace_subtract */
142      0,                       /* nb_inplace_multiply */
143      0,                       /* nb_inplace_remainder */
144      0,                       /* nb_inplace_power */
145      0,                       /* nb_inplace_lshift */
146      0,                       /* nb_inplace_rshift */
147      0,                       /* nb_inplace_and */
148      0,                       /* nb_inplace_xor */
149      0,                       /* nb_inplace_or */
150 
151      0,                       /* nb_floor_divide */
152      0,                       /* nb_true_divide */
153      0,                       /* nb_inplace_floor_divide */
154      0,                       /* nb_inplace_true_divide */
155 
156      (unaryfunc)interpid_int, /* nb_index */
157 };
158 
159 static Py_hash_t
interpid_hash(PyObject * self)160 interpid_hash(PyObject *self)
161 {
162     interpid *id = (interpid *)self;
163     PyObject *obj = PyLong_FromLongLong(id->id);
164     if (obj == NULL) {
165         return -1;
166     }
167     Py_hash_t hash = PyObject_Hash(obj);
168     Py_DECREF(obj);
169     return hash;
170 }
171 
172 static PyObject *
interpid_richcompare(PyObject * self,PyObject * other,int op)173 interpid_richcompare(PyObject *self, PyObject *other, int op)
174 {
175     if (op != Py_EQ && op != Py_NE) {
176         Py_RETURN_NOTIMPLEMENTED;
177     }
178 
179     if (!PyObject_TypeCheck(self, &_PyInterpreterID_Type)) {
180         Py_RETURN_NOTIMPLEMENTED;
181     }
182 
183     interpid *id = (interpid *)self;
184     int equal;
185     if (PyObject_TypeCheck(other, &_PyInterpreterID_Type)) {
186         interpid *otherid = (interpid *)other;
187         equal = (id->id == otherid->id);
188     }
189     else if (PyLong_CheckExact(other)) {
190         /* Fast path */
191         int overflow;
192         long long otherid = PyLong_AsLongLongAndOverflow(other, &overflow);
193         if (otherid == -1 && PyErr_Occurred()) {
194             return NULL;
195         }
196         equal = !overflow && (otherid >= 0) && (id->id == otherid);
197     }
198     else if (PyNumber_Check(other)) {
199         PyObject *pyid = PyLong_FromLongLong(id->id);
200         if (pyid == NULL) {
201             return NULL;
202         }
203         PyObject *res = PyObject_RichCompare(pyid, other, op);
204         Py_DECREF(pyid);
205         return res;
206     }
207     else {
208         Py_RETURN_NOTIMPLEMENTED;
209     }
210 
211     if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
212         Py_RETURN_TRUE;
213     }
214     Py_RETURN_FALSE;
215 }
216 
217 PyDoc_STRVAR(interpid_doc,
218 "A interpreter ID identifies a interpreter and may be used as an int.");
219 
220 PyTypeObject _PyInterpreterID_Type = {
221     PyVarObject_HEAD_INIT(&PyType_Type, 0)
222     "InterpreterID",   /* tp_name */
223     sizeof(interpid),               /* tp_basicsize */
224     0,                              /* tp_itemsize */
225     (destructor)interpid_dealloc,   /* tp_dealloc */
226     0,                              /* tp_vectorcall_offset */
227     0,                              /* tp_getattr */
228     0,                              /* tp_setattr */
229     0,                              /* tp_as_async */
230     (reprfunc)interpid_repr,        /* tp_repr */
231     &interpid_as_number,            /* tp_as_number */
232     0,                              /* tp_as_sequence */
233     0,                              /* tp_as_mapping */
234     interpid_hash,                  /* tp_hash */
235     0,                              /* tp_call */
236     (reprfunc)interpid_str,         /* tp_str */
237     0,                              /* tp_getattro */
238     0,                              /* tp_setattro */
239     0,                              /* tp_as_buffer */
240     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
241     interpid_doc,                   /* tp_doc */
242     0,                              /* tp_traverse */
243     0,                              /* tp_clear */
244     interpid_richcompare,           /* tp_richcompare */
245     0,                              /* tp_weaklistoffset */
246     0,                              /* tp_iter */
247     0,                              /* tp_iternext */
248     0,                              /* tp_methods */
249     0,                              /* tp_members */
250     0,                              /* tp_getset */
251     0,                              /* tp_base */
252     0,                              /* tp_dict */
253     0,                              /* tp_descr_get */
254     0,                              /* tp_descr_set */
255     0,                              /* tp_dictoffset */
256     0,                              /* tp_init */
257     0,                              /* tp_alloc */
258     interpid_new,                   /* tp_new */
259 };
260 
_PyInterpreterID_New(int64_t id)261 PyObject *_PyInterpreterID_New(int64_t id)
262 {
263     return (PyObject *)newinterpid(&_PyInterpreterID_Type, id, 0);
264 }
265 
266 PyObject *
_PyInterpreterState_GetIDObject(PyInterpreterState * interp)267 _PyInterpreterState_GetIDObject(PyInterpreterState *interp)
268 {
269     if (_PyInterpreterState_IDInitref(interp) != 0) {
270         return NULL;
271     };
272     PY_INT64_T id = PyInterpreterState_GetID(interp);
273     if (id < 0) {
274         return NULL;
275     }
276     return (PyObject *)newinterpid(&_PyInterpreterID_Type, id, 0);
277 }
278 
279 PyInterpreterState *
_PyInterpreterID_LookUp(PyObject * requested_id)280 _PyInterpreterID_LookUp(PyObject *requested_id)
281 {
282     int64_t id;
283     if (!interp_id_converter(requested_id, &id)) {
284         return NULL;
285     }
286     return _PyInterpreterState_LookUpID(id);
287 }
288