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