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