History

add hg and python

cinap_lenrek committed 15 years ago

Commit 4bb9e221 parent 987265c3706 files · +1228772 −-233Browse files

Showing the changes to sys/src/cmd/python/Modules/threadmodule.c (1 of 3706 files). Show all

Unified · Split

sys/src/cmd/python/Modules/threadmodule.c+720−0
@@ -0,0 +1,720 @@
1
2/* Thread module */
3/* Interface to Sjoerd's portable C thread library */
4
5#include "Python.h"
6
7#ifndef WITH_THREAD
8#error "Error! The rest of Python is not compiled with thread support."
9#error "Rerun configure, adding a --with-threads option."
10#error "Then run `make clean' followed by `make'."
11#endif
12
13#include "pythread.h"
14
15static PyObject *ThreadError;
16
17
18/* Lock objects */
19
20typedef struct {
21 PyObject_HEAD
22 PyThread_type_lock lock_lock;
23} lockobject;
24
25static void
26lock_dealloc(lockobject *self)
27{
28 assert(self->lock_lock);
29 /* Unlock the lock so it's safe to free it */
30 PyThread_acquire_lock(self->lock_lock, 0);
31 PyThread_release_lock(self->lock_lock);
32
33 PyThread_free_lock(self->lock_lock);
34 PyObject_Del(self);
35}
36
37static PyObject *
38lock_PyThread_acquire_lock(lockobject *self, PyObject *args)
39{
40 int i = 1;
41
42 if (!PyArg_ParseTuple(args, "|i:acquire", &i))
43 return NULL;
44
45 Py_BEGIN_ALLOW_THREADS
46 i = PyThread_acquire_lock(self->lock_lock, i);
47 Py_END_ALLOW_THREADS
48
49 return PyBool_FromLong((long)i);
50}
51
52PyDoc_STRVAR(acquire_doc,
53"acquire([wait]) -> None or bool\n\
54(acquire_lock() is an obsolete synonym)\n\
55\n\
56Lock the lock. Without argument, this blocks if the lock is already\n\
57locked (even by the same thread), waiting for another thread to release\n\
58the lock, and return None once the lock is acquired.\n\
59With an argument, this will only block if the argument is true,\n\
60and the return value reflects whether the lock is acquired.\n\
61The blocking operation is not interruptible.");
62
63static PyObject *
64lock_PyThread_release_lock(lockobject *self)
65{
66 /* Sanity check: the lock must be locked */
67 if (PyThread_acquire_lock(self->lock_lock, 0)) {
68 PyThread_release_lock(self->lock_lock);
69 PyErr_SetString(ThreadError, "release unlocked lock");
70 return NULL;
71 }
72
73 PyThread_release_lock(self->lock_lock);
74 Py_INCREF(Py_None);
75 return Py_None;
76}
77
78PyDoc_STRVAR(release_doc,
79"release()\n\
80(release_lock() is an obsolete synonym)\n\
81\n\
82Release the lock, allowing another thread that is blocked waiting for\n\
83the lock to acquire the lock. The lock must be in the locked state,\n\
84but it needn't be locked by the same thread that unlocks it.");
85
86static PyObject *
87lock_locked_lock(lockobject *self)
88{
89 if (PyThread_acquire_lock(self->lock_lock, 0)) {
90 PyThread_release_lock(self->lock_lock);
91 return PyBool_FromLong(0L);
92 }
93 return PyBool_FromLong(1L);
94}
95
96PyDoc_STRVAR(locked_doc,
97"locked() -> bool\n\
98(locked_lock() is an obsolete synonym)\n\
99\n\
100Return whether the lock is in the locked state.");
101
102static PyMethodDef lock_methods[] = {
103 {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
104 METH_VARARGS, acquire_doc},
105 {"acquire", (PyCFunction)lock_PyThread_acquire_lock,
106 METH_VARARGS, acquire_doc},
107 {"release_lock", (PyCFunction)lock_PyThread_release_lock,
108 METH_NOARGS, release_doc},
109 {"release", (PyCFunction)lock_PyThread_release_lock,
110 METH_NOARGS, release_doc},
111 {"locked_lock", (PyCFunction)lock_locked_lock,
112 METH_NOARGS, locked_doc},
113 {"locked", (PyCFunction)lock_locked_lock,
114 METH_NOARGS, locked_doc},
115 {"__enter__", (PyCFunction)lock_PyThread_acquire_lock,
116 METH_VARARGS, acquire_doc},
117 {"__exit__", (PyCFunction)lock_PyThread_release_lock,
118 METH_VARARGS, release_doc},
119 {NULL, NULL} /* sentinel */
120};
121
122static PyObject *
123lock_getattr(lockobject *self, char *name)
124{
125 return Py_FindMethod(lock_methods, (PyObject *)self, name);
126}
127
128static PyTypeObject Locktype = {
129 PyObject_HEAD_INIT(&PyType_Type)
130 0, /*ob_size*/
131 "thread.lock", /*tp_name*/
132 sizeof(lockobject), /*tp_size*/
133 0, /*tp_itemsize*/
134 /* methods */
135 (destructor)lock_dealloc, /*tp_dealloc*/
136 0, /*tp_print*/
137 (getattrfunc)lock_getattr, /*tp_getattr*/
138 0, /*tp_setattr*/
139 0, /*tp_compare*/
140 0, /*tp_repr*/
141};
142
143static lockobject *
144newlockobject(void)
145{
146 lockobject *self;
147 self = PyObject_New(lockobject, &Locktype);
148 if (self == NULL)
149 return NULL;
150 self->lock_lock = PyThread_allocate_lock();
151 if (self->lock_lock == NULL) {
152 PyObject_Del(self);
153 self = NULL;
154 PyErr_SetString(ThreadError, "can't allocate lock");
155 }
156 return self;
157}
158
159/* Thread-local objects */
160
161#include "structmember.h"
162
163typedef struct {
164 PyObject_HEAD
165 PyObject *key;
166 PyObject *args;
167 PyObject *kw;
168 PyObject *dict;
169} localobject;
170
171static PyObject *
172local_new(PyTypeObject *type, PyObject *args, PyObject *kw)
173{
174 localobject *self;
175 PyObject *tdict;
176
177 if (type->tp_init == PyBaseObject_Type.tp_init
178 && ((args && PyObject_IsTrue(args))
179 || (kw && PyObject_IsTrue(kw)))) {
180 PyErr_SetString(PyExc_TypeError,
181 "Initialization arguments are not supported");
182 return NULL;
183 }
184
185 self = (localobject *)type->tp_alloc(type, 0);
186 if (self == NULL)
187 return NULL;
188
189 Py_XINCREF(args);
190 self->args = args;
191 Py_XINCREF(kw);
192 self->kw = kw;
193 self->dict = NULL; /* making sure */
194 self->key = PyString_FromFormat("thread.local.%p", self);
195 if (self->key == NULL)
196 goto err;
197
198 self->dict = PyDict_New();
199 if (self->dict == NULL)
200 goto err;
201
202 tdict = PyThreadState_GetDict();
203 if (tdict == NULL) {
204 PyErr_SetString(PyExc_SystemError,
205 "Couldn't get thread-state dictionary");
206 goto err;
207 }
208
209 if (PyDict_SetItem(tdict, self->key, self->dict) < 0)
210 goto err;
211
212 return (PyObject *)self;
213
214 err:
215 Py_DECREF(self);
216 return NULL;
217}
218
219static int
220local_traverse(localobject *self, visitproc visit, void *arg)
221{
222 Py_VISIT(self->args);
223 Py_VISIT(self->kw);
224 Py_VISIT(self->dict);
225 return 0;
226}
227
228static int
229local_clear(localobject *self)
230{
231 Py_CLEAR(self->key);
232 Py_CLEAR(self->args);
233 Py_CLEAR(self->kw);
234 Py_CLEAR(self->dict);
235 return 0;
236}
237
238static void
239local_dealloc(localobject *self)
240{
241 PyThreadState *tstate;
242 if (self->key
243 && (tstate = PyThreadState_Get())
244 && tstate->interp) {
245 for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
246 tstate;
247 tstate = PyThreadState_Next(tstate))
248 if (tstate->dict &&
249 PyDict_GetItem(tstate->dict, self->key))
250 PyDict_DelItem(tstate->dict, self->key);
251 }
252
253 local_clear(self);
254 self->ob_type->tp_free((PyObject*)self);
255}
256
257static PyObject *
258_ldict(localobject *self)
259{
260 PyObject *tdict, *ldict;
261
262 tdict = PyThreadState_GetDict();
263 if (tdict == NULL) {
264 PyErr_SetString(PyExc_SystemError,
265 "Couldn't get thread-state dictionary");
266 return NULL;
267 }
268
269 ldict = PyDict_GetItem(tdict, self->key);
270 if (ldict == NULL) {
271 ldict = PyDict_New(); /* we own ldict */
272
273 if (ldict == NULL)
274 return NULL;
275 else {
276 int i = PyDict_SetItem(tdict, self->key, ldict);
277 Py_DECREF(ldict); /* now ldict is borrowed */
278 if (i < 0)
279 return NULL;
280 }
281
282 Py_CLEAR(self->dict);
283 Py_INCREF(ldict);
284 self->dict = ldict; /* still borrowed */
285
286 if (self->ob_type->tp_init != PyBaseObject_Type.tp_init &&
287 self->ob_type->tp_init((PyObject*)self,
288 self->args, self->kw) < 0) {
289 /* we need to get rid of ldict from thread so
290 we create a new one the next time we do an attr
291 acces */
292 PyDict_DelItem(tdict, self->key);
293 return NULL;
294 }
295
296 }
297 else if (self->dict != ldict) {
298 Py_CLEAR(self->dict);
299 Py_INCREF(ldict);
300 self->dict = ldict;
301 }
302
303 return ldict;
304}
305
306static int
307local_setattro(localobject *self, PyObject *name, PyObject *v)
308{
309 PyObject *ldict;
310
311 ldict = _ldict(self);
312 if (ldict == NULL)
313 return -1;
314
315 return PyObject_GenericSetAttr((PyObject *)self, name, v);
316}
317
318static PyObject *
319local_getdict(localobject *self, void *closure)
320{
321 if (self->dict == NULL) {
322 PyErr_SetString(PyExc_AttributeError, "__dict__");
323 return NULL;
324 }
325
326 Py_INCREF(self->dict);
327 return self->dict;
328}
329
330static PyGetSetDef local_getset[] = {
331 {"__dict__", (getter)local_getdict, (setter)NULL,
332 "Local-data dictionary", NULL},
333 {NULL} /* Sentinel */
334};
335
336static PyObject *local_getattro(localobject *, PyObject *);
337
338static PyTypeObject localtype = {
339 PyObject_HEAD_INIT(NULL)
340 /* ob_size */ 0,
341 /* tp_name */ "thread._local",
342 /* tp_basicsize */ sizeof(localobject),
343 /* tp_itemsize */ 0,
344 /* tp_dealloc */ (destructor)local_dealloc,
345 /* tp_print */ 0,
346 /* tp_getattr */ 0,
347 /* tp_setattr */ 0,
348 /* tp_compare */ 0,
349 /* tp_repr */ 0,
350 /* tp_as_number */ 0,
351 /* tp_as_sequence */ 0,
352 /* tp_as_mapping */ 0,
353 /* tp_hash */ 0,
354 /* tp_call */ 0,
355 /* tp_str */ 0,
356 /* tp_getattro */ (getattrofunc)local_getattro,
357 /* tp_setattro */ (setattrofunc)local_setattro,
358 /* tp_as_buffer */ 0,
359 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
360 /* tp_doc */ "Thread-local data",
361 /* tp_traverse */ (traverseproc)local_traverse,
362 /* tp_clear */ (inquiry)local_clear,
363 /* tp_richcompare */ 0,
364 /* tp_weaklistoffset */ 0,
365 /* tp_iter */ 0,
366 /* tp_iternext */ 0,
367 /* tp_methods */ 0,
368 /* tp_members */ 0,
369 /* tp_getset */ local_getset,
370 /* tp_base */ 0,
371 /* tp_dict */ 0, /* internal use */
372 /* tp_descr_get */ 0,
373 /* tp_descr_set */ 0,
374 /* tp_dictoffset */ offsetof(localobject, dict),
375 /* tp_init */ 0,
376 /* tp_alloc */ 0,
377 /* tp_new */ local_new,
378 /* tp_free */ 0, /* Low-level free-mem routine */
379 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
380};
381
382static PyObject *
383local_getattro(localobject *self, PyObject *name)
384{
385 PyObject *ldict, *value;
386
387 ldict = _ldict(self);
388 if (ldict == NULL)
389 return NULL;
390
391 if (self->ob_type != &localtype)
392 /* use generic lookup for subtypes */
393 return PyObject_GenericGetAttr((PyObject *)self, name);
394
395 /* Optimization: just look in dict ourselves */
396 value = PyDict_GetItem(ldict, name);
397 if (value == NULL)
398 /* Fall back on generic to get __class__ and __dict__ */
399 return PyObject_GenericGetAttr((PyObject *)self, name);
400
401 Py_INCREF(value);
402 return value;
403}
404
405/* Module functions */
406
407struct bootstate {
408 PyInterpreterState *interp;
409 PyObject *func;
410 PyObject *args;
411 PyObject *keyw;
412};
413
414static void
415t_bootstrap(void *boot_raw)
416{
417 struct bootstate *boot = (struct bootstate *) boot_raw;
418 PyThreadState *tstate;
419 PyObject *res;
420
421 tstate = PyThreadState_New(boot->interp);
422
423 PyEval_AcquireThread(tstate);
424 res = PyEval_CallObjectWithKeywords(
425 boot->func, boot->args, boot->keyw);
426 if (res == NULL) {
427 if (PyErr_ExceptionMatches(PyExc_SystemExit))
428 PyErr_Clear();
429 else {
430 PyObject *file;
431 PySys_WriteStderr(
432 "Unhandled exception in thread started by ");
433 file = PySys_GetObject("stderr");
434 if (file)
435 PyFile_WriteObject(boot->func, file, 0);
436 else
437 PyObject_Print(boot->func, stderr, 0);
438 PySys_WriteStderr("\n");
439 PyErr_PrintEx(0);
440 }
441 }
442 else
443 Py_DECREF(res);
444 Py_DECREF(boot->func);
445 Py_DECREF(boot->args);
446 Py_XDECREF(boot->keyw);
447 PyMem_DEL(boot_raw);
448 PyThreadState_Clear(tstate);
449 PyThreadState_DeleteCurrent();
450 PyThread_exit_thread();
451}
452
453static PyObject *
454thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
455{
456 PyObject *func, *args, *keyw = NULL;
457 struct bootstate *boot;
458 long ident;
459
460 if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
461 &func, &args, &keyw))
462 return NULL;
463 if (!PyCallable_Check(func)) {
464 PyErr_SetString(PyExc_TypeError,
465 "first arg must be callable");
466 return NULL;
467 }
468 if (!PyTuple_Check(args)) {
469 PyErr_SetString(PyExc_TypeError,
470 "2nd arg must be a tuple");
471 return NULL;
472 }
473 if (keyw != NULL && !PyDict_Check(keyw)) {
474 PyErr_SetString(PyExc_TypeError,
475 "optional 3rd arg must be a dictionary");
476 return NULL;
477 }
478 boot = PyMem_NEW(struct bootstate, 1);
479 if (boot == NULL)
480 return PyErr_NoMemory();
481 boot->interp = PyThreadState_GET()->interp;
482 boot->func = func;
483 boot->args = args;
484 boot->keyw = keyw;
485 Py_INCREF(func);
486 Py_INCREF(args);
487 Py_XINCREF(keyw);
488 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
489 ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
490 if (ident == -1) {
491 PyErr_SetString(ThreadError, "can't start new thread");
492 Py_DECREF(func);
493 Py_DECREF(args);
494 Py_XDECREF(keyw);
495 PyMem_DEL(boot);
496 return NULL;
497 }
498 return PyInt_FromLong(ident);
499}
500
501PyDoc_STRVAR(start_new_doc,
502"start_new_thread(function, args[, kwargs])\n\
503(start_new() is an obsolete synonym)\n\
504\n\
505Start a new thread and return its identifier. The thread will call the\n\
506function with positional arguments from the tuple args and keyword arguments\n\
507taken from the optional dictionary kwargs. The thread exits when the\n\
508function returns; the return value is ignored. The thread will also exit\n\
509when the function raises an unhandled exception; a stack trace will be\n\
510printed unless the exception is SystemExit.\n");
511
512static PyObject *
513thread_PyThread_exit_thread(PyObject *self)
514{
515 PyErr_SetNone(PyExc_SystemExit);
516 return NULL;
517}
518
519PyDoc_STRVAR(exit_doc,
520"exit()\n\
521(PyThread_exit_thread() is an obsolete synonym)\n\
522\n\
523This is synonymous to ``raise SystemExit''. It will cause the current\n\
524thread to exit silently unless the exception is caught.");
525
526static PyObject *
527thread_PyThread_interrupt_main(PyObject * self)
528{
529 PyErr_SetInterrupt();
530 Py_INCREF(Py_None);
531 return Py_None;
532}
533
534PyDoc_STRVAR(interrupt_doc,
535"interrupt_main()\n\
536\n\
537Raise a KeyboardInterrupt in the main thread.\n\
538A subthread can use this function to interrupt the main thread."
539);
540
541#ifndef NO_EXIT_PROG
542static PyObject *
543thread_PyThread_exit_prog(PyObject *self, PyObject *args)
544{
545 int sts;
546 if (!PyArg_ParseTuple(args, "i:exit_prog", &sts))
547 return NULL;
548 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
549 for (;;) { } /* Should not be reached */
550}
551#endif
552
553static lockobject *newlockobject(void);
554
555static PyObject *
556thread_PyThread_allocate_lock(PyObject *self)
557{
558 return (PyObject *) newlockobject();
559}
560
561PyDoc_STRVAR(allocate_doc,
562"allocate_lock() -> lock object\n\
563(allocate() is an obsolete synonym)\n\
564\n\
565Create a new lock object. See LockType.__doc__ for information about locks.");
566
567static PyObject *
568thread_get_ident(PyObject *self)
569{
570 long ident;
571 ident = PyThread_get_thread_ident();
572 if (ident == -1) {
573 PyErr_SetString(ThreadError, "no current thread ident");
574 return NULL;
575 }
576 return PyInt_FromLong(ident);
577}
578
579PyDoc_STRVAR(get_ident_doc,
580"get_ident() -> integer\n\
581\n\
582Return a non-zero integer that uniquely identifies the current thread\n\
583amongst other threads that exist simultaneously.\n\
584This may be used to identify per-thread resources.\n\
585Even though on some platforms threads identities may appear to be\n\
586allocated consecutive numbers starting at 1, this behavior should not\n\
587be relied upon, and the number should be seen purely as a magic cookie.\n\
588A thread's identity may be reused for another thread after it exits.");
589
590static PyObject *
591thread_stack_size(PyObject *self, PyObject *args)
592{
593 size_t old_size;
594 Py_ssize_t new_size = 0;
595 int rc;
596
597 if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
598 return NULL;
599
600 if (new_size < 0) {
601 PyErr_SetString(PyExc_ValueError,
602 "size must be 0 or a positive value");
603 return NULL;
604 }
605
606 old_size = PyThread_get_stacksize();
607
608 rc = PyThread_set_stacksize((size_t) new_size);
609 if (rc == -1) {
610 PyErr_Format(PyExc_ValueError,
611 "size not valid: %zd bytes",
612 new_size);
613 return NULL;
614 }
615 if (rc == -2) {
616 PyErr_SetString(ThreadError,
617 "setting stack size not supported");
618 return NULL;
619 }
620
621 return PyInt_FromSsize_t((Py_ssize_t) old_size);
622}
623
624PyDoc_STRVAR(stack_size_doc,
625"stack_size([size]) -> size\n\
626\n\
627Return the thread stack size used when creating new threads. The\n\
628optional size argument specifies the stack size (in bytes) to be used\n\
629for subsequently created threads, and must be 0 (use platform or\n\
630configured default) or a positive integer value of at least 32,768 (32k).\n\
631If changing the thread stack size is unsupported, a ThreadError\n\
632exception is raised. If the specified size is invalid, a ValueError\n\
633exception is raised, and the stack size is unmodified. 32k bytes\n\
634 currently the minimum supported stack size value to guarantee\n\
635sufficient stack space for the interpreter itself.\n\
636\n\
637Note that some platforms may have particular restrictions on values for\n\
638the stack size, such as requiring a minimum stack size larger than 32kB or\n\
639requiring allocation in multiples of the system memory page size\n\
640- platform documentation should be referred to for more information\n\
641(4kB pages are common; using multiples of 4096 for the stack size is\n\
642the suggested approach in the absence of more specific information).");
643
644static PyMethodDef thread_methods[] = {
645 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
646 METH_VARARGS,
647 start_new_doc},
648 {"start_new", (PyCFunction)thread_PyThread_start_new_thread,
649 METH_VARARGS,
650 start_new_doc},
651 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
652 METH_NOARGS, allocate_doc},
653 {"allocate", (PyCFunction)thread_PyThread_allocate_lock,
654 METH_NOARGS, allocate_doc},
655 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread,
656 METH_NOARGS, exit_doc},
657 {"exit", (PyCFunction)thread_PyThread_exit_thread,
658 METH_NOARGS, exit_doc},
659 {"interrupt_main", (PyCFunction)thread_PyThread_interrupt_main,
660 METH_NOARGS, interrupt_doc},
661 {"get_ident", (PyCFunction)thread_get_ident,
662 METH_NOARGS, get_ident_doc},
663 {"stack_size", (PyCFunction)thread_stack_size,
664 METH_VARARGS,
665 stack_size_doc},
666#ifndef NO_EXIT_PROG
667 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog,
668 METH_VARARGS},
669#endif
670 {NULL, NULL} /* sentinel */
671};
672
673
674/* Initialization function */
675
676PyDoc_STRVAR(thread_doc,
677"This module provides primitive operations to write multi-threaded programs.\n\
678The 'threading' module provides a more convenient interface.");
679
680PyDoc_STRVAR(lock_doc,
681"A lock object is a synchronization primitive. To create a lock,\n\
682call the PyThread_allocate_lock() function. Methods are:\n\
683\n\
684acquire() -- lock the lock, possibly blocking until it can be obtained\n\
685release() -- unlock of the lock\n\
686locked() -- test whether the lock is currently locked\n\
687\n\
688A lock is not owned by the thread that locked it; another thread may\n\
689unlock it. A thread attempting to lock a lock that it has already locked\n\
690will block until another thread unlocks it. Deadlocks may ensue.");
691
692PyMODINIT_FUNC
693initthread(void)
694{
695 PyObject *m, *d;
696
697 /* Initialize types: */
698 if (PyType_Ready(&localtype) < 0)
699 return;
700
701 /* Create the module and add the functions */
702 m = Py_InitModule3("thread", thread_methods, thread_doc);
703 if (m == NULL)
704 return;
705
706 /* Add a symbolic constant */
707 d = PyModule_GetDict(m);
708 ThreadError = PyErr_NewException("thread.error", NULL, NULL);
709 PyDict_SetItemString(d, "error", ThreadError);
710 Locktype.tp_doc = lock_doc;
711 Py_INCREF(&Locktype);
712 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
713
714 Py_INCREF(&localtype);
715 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
716 return;
717
718 /* Initialize the C thread library */
719 PyThread_init_thread();
720}