/* Thread package.This is intended to be usable independently from Python.The implementation for system foobar is in a file thread_foobar.hwhich is included by this file dependent on config settings.Stuff shared by all thread_*.h files is collected here. */#include "Python.h"#ifndef _POSIX_THREADS/* This means pthreads are not implemented in libc headers, hence the macronot present in unistd.h. But they still can be implemented as an externallibrary (e.g. gnu pth in pthread emulation) */# ifdef HAVE_PTHREAD_H# include <pthread.h> /* _POSIX_THREADS */# endif#endif#ifndef DONT_HAVE_STDIO_H#include <stdio.h>#endif#include <stdlib.h>#ifdef __sgi#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */#undef _POSIX_THREADS#endif#endif#include "pythread.h"#ifndef _POSIX_THREADS#ifdef __sgi#define SGI_THREADS#endif#ifdef HAVE_THREAD_H#define SOLARIS_THREADS#endif#if defined(sun) && !defined(SOLARIS_THREADS)#define SUN_LWP#endif/* Check if we're running on HP-UX and _SC_THREADS is defined. If so, thenenough of the Posix threads package is implimented to support pythonthreads.This is valid for HP-UX 11.23 running on an ia64 system. If needed, adda check of __ia64 to verify that we're running on a ia64 system insteadof a pa-risc system.*/#ifdef __hpux#ifdef _SC_THREADS#define _POSIX_THREADS#endif#endif#endif /* _POSIX_THREADS */#ifdef Py_DEBUGstatic int thread_debug = 0;#define dprintf(args) (void)((thread_debug & 1) && printf args)#define d2printf(args) ((thread_debug & 8) && printf args)#else#define dprintf(args)#define d2printf(args)#endifstatic int initialized;static void PyThread__init_thread(void); /* Forward */voidPyThread_init_thread(void){#ifdef Py_DEBUGchar *p = Py_GETENV("PYTHONTHREADDEBUG");if (p) {if (*p)thread_debug = atoi(p);elsethread_debug = 1;}#endif /* Py_DEBUG */if (initialized)return;initialized = 1;dprintf(("PyThread_init_thread called\n"));PyThread__init_thread();}/* Support for runtime thread stack size tuning.A value of 0 means using the platform's default stack sizeor the size specified by the THREAD_STACK_SIZE macro. */static size_t _pythread_stacksize = 0;#ifdef SGI_THREADS#include "thread_sgi.h"#endif#ifdef SOLARIS_THREADS#include "thread_solaris.h"#endif#ifdef SUN_LWP#include "thread_lwp.h"#endif#ifdef HAVE_PTH#include "thread_pth.h"#undef _POSIX_THREADS#endif#ifdef _POSIX_THREADS#include "thread_pthread.h"#endif#ifdef C_THREADS#include "thread_cthread.h"#endif#ifdef NT_THREADS#include "thread_nt.h"#endif#ifdef OS2_THREADS#include "thread_os2.h"#endif#ifdef BEOS_THREADS#include "thread_beos.h"#endif#ifdef PLAN9_THREADS#include "thread_plan9.h"#endif#ifdef ATHEOS_THREADS#include "thread_atheos.h"#endif/*#ifdef FOOBAR_THREADS#include "thread_foobar.h"#endif*//* return the current thread stack size */size_tPyThread_get_stacksize(void){return _pythread_stacksize;}/* Only platforms defining a THREAD_SET_STACKSIZE() macroin thread_<platform>.h support changing the stack size.Return 0 if stack size is valid,-1 if stack size value is invalid,-2 if setting stack size is not supported. */intPyThread_set_stacksize(size_t size){#if defined(THREAD_SET_STACKSIZE)return THREAD_SET_STACKSIZE(size);#elsereturn -2;#endif}#ifndef Py_HAVE_NATIVE_TLS/* If the platform has not supplied a platform specificTLS implementation, provide our own.This code stolen from "thread_sgi.h", where it was the onlyimplementation of an existing Python TLS API.*//* ------------------------------------------------------------------------Per-thread data ("key") support.Use PyThread_create_key() to create a new key. This is typically sharedacross threads.Use PyThread_set_key_value(thekey, value) to associate void* value withthekey in the current thread. Each thread has a distinct mapping of thekeyto a void* value. Caution: if the current thread already has a mappingfor thekey, value is ignored.Use PyThread_get_key_value(thekey) to retrieve the void* value associatedwith thekey in the current thread. This returns NULL if no value isassociated with thekey in the current thread.Use PyThread_delete_key_value(thekey) to forget the current thread's associatedvalue for thekey. PyThread_delete_key(thekey) forgets the values associatedwith thekey across *all* threads.While some of these functions have error-return values, none set anyPython exception.None of the functions does memory management on behalf of the void* values.You need to allocate and deallocate them yourself. If the void* valueshappen to be PyObject*, these functions don't do refcount operations onthem either.The GIL does not need to be held when calling these functions; they supplytheir own locking. This isn't true of PyThread_create_key(), though (seenext paragraph).There's a hidden assumption that PyThread_create_key() will be called beforeany of the other functions are called. There's also a hidden assumptionthat calls to PyThread_create_key() are serialized externally.------------------------------------------------------------------------ *//* A singly-linked list of struct key objects remembers all the key->value* associations. File static keyhead heads the list. keymutex is used* to enforce exclusion internally.*/struct key {/* Next record in the list, or NULL if this is the last record. */struct key *next;/* The thread id, according to PyThread_get_thread_ident(). */long id;/* The key and its associated value. */int key;void *value;};static struct key *keyhead = NULL;static PyThread_type_lock keymutex = NULL;static int nkeys = 0; /* PyThread_create_key() hands out nkeys+1 next *//* Internal helper.* If the current thread has a mapping for key, the appropriate struct key** is returned. NB: value is ignored in this case!* If there is no mapping for key in the current thread, then:* If value is NULL, NULL is returned.* Else a mapping of key to value is created for the current thread,* and a pointer to a new struct key* is returned; except that if* malloc() can't find room for a new struct key*, NULL is returned.* So when value==NULL, this acts like a pure lookup routine, and when* value!=NULL, this acts like dict.setdefault(), returning an existing* mapping if one exists, else creating a new mapping.** Caution: this used to be too clever, trying to hold keymutex only* around the "p->next = keyhead; keyhead = p" pair. That allowed* another thread to mutate the list, via key deletion, concurrent with* find_key() crawling over the list. Hilarity ensued. For example, when* the for-loop here does "p = p->next", p could end up pointing at a* record that PyThread_delete_key_value() was concurrently free()'ing.* That could lead to anything, from failing to find a key that exists, to* segfaults. Now we lock the whole routine.*/static struct key *find_key(int key, void *value){struct key *p, *prev_p;long id = PyThread_get_thread_ident();if (!keymutex)return NULL;PyThread_acquire_lock(keymutex, 1);prev_p = NULL;for (p = keyhead; p != NULL; p = p->next) {if (p->id == id && p->key == key)goto Done;/* Sanity check. These states should never happen but if* they do we must abort. Otherwise we'll end up spinning in* in a tight loop with the lock held. A similar check is done* in pystate.c tstate_delete_common(). */if (p == prev_p)Py_FatalError("tls find_key: small circular list(!)");prev_p = p;if (p->next == keyhead)Py_FatalError("tls find_key: circular list(!)");}if (value == NULL) {assert(p == NULL);goto Done;}p = (struct key *)malloc(sizeof(struct key));if (p != NULL) {p->id = id;p->key = key;p->value = value;p->next = keyhead;keyhead = p;}Done:PyThread_release_lock(keymutex);return p;}/* Return a new key. This must be called before any other functions in* this family, and callers must arrange to serialize calls to this* function. No violations are detected.*/intPyThread_create_key(void){/* All parts of this function are wrong if it's called by multiple* threads simultaneously.*/if (keymutex == NULL)keymutex = PyThread_allocate_lock();return ++nkeys;}/* Forget the associations for key across *all* threads. */voidPyThread_delete_key(int key){struct key *p, **q;PyThread_acquire_lock(keymutex, 1);q = &keyhead;while ((p = *q) != NULL) {if (p->key == key) {*q = p->next;free((void *)p);/* NB This does *not* free p->value! */}elseq = &p->next;}PyThread_release_lock(keymutex);}/* Confusing: If the current thread has an association for key,* value is ignored, and 0 is returned. Else an attempt is made to create* an association of key to value for the current thread. 0 is returned* if that succeeds, but -1 is returned if there's not enough memory* to create the association. value must not be NULL.*/intPyThread_set_key_value(int key, void *value){struct key *p;assert(value != NULL);p = find_key(key, value);if (p == NULL)return -1;elsereturn 0;}/* Retrieve the value associated with key in the current thread, or NULL* if the current thread doesn't have an association for key.*/void *PyThread_get_key_value(int key){struct key *p = find_key(key, NULL);if (p == NULL)return NULL;elsereturn p->value;}/* Forget the current thread's association for key, if any. */voidPyThread_delete_key_value(int key){long id = PyThread_get_thread_ident();struct key *p, **q;PyThread_acquire_lock(keymutex, 1);q = &keyhead;while ((p = *q) != NULL) {if (p->key == key && p->id == id) {*q = p->next;free((void *)p);/* NB This does *not* free p->value! */break;}elseq = &p->next;}PyThread_release_lock(keymutex);}/* Forget everything not associated with the current thread id.* This function is called from PyOS_AfterFork(). It is necessary* because other thread ids which were in use at the time of the fork* may be reused for new threads created in the forked process.*/voidPyThread_ReInitTLS(void){long id = PyThread_get_thread_ident();struct key *p, **q;if (!keymutex)return;/* As with interpreter_lock in PyEval_ReInitThreads()we just create a new lock without freeing the old one */keymutex = PyThread_allocate_lock();/* Delete all keys which do not match the current thread id */q = &keyhead;while ((p = *q) != NULL) {if (p->id != id) {*q = p->next;free((void *)p);/* NB This does *not* free p->value! */}elseq = &p->next;}}#endif /* Py_HAVE_NATIVE_TLS */
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。