mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	Issue #17912: Use a doubly linked-list for thread states.
This commit is contained in:
		
							parent
							
								
									04e70d19e7
								
							
						
					
					
						commit
						f28dfdd07b
					
				
					 2 changed files with 18 additions and 41 deletions
				
			
		|  | @ -69,6 +69,7 @@ typedef struct _ts PyThreadState; | ||||||
| typedef struct _ts { | typedef struct _ts { | ||||||
|     /* See Python/ceval.c for comments explaining most fields */ |     /* See Python/ceval.c for comments explaining most fields */ | ||||||
| 
 | 
 | ||||||
|  |     struct _ts *prev; | ||||||
|     struct _ts *next; |     struct _ts *next; | ||||||
|     PyInterpreterState *interp; |     PyInterpreterState *interp; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -213,7 +213,10 @@ new_threadstate(PyInterpreterState *interp, int init) | ||||||
|             _PyThreadState_Init(tstate); |             _PyThreadState_Init(tstate); | ||||||
| 
 | 
 | ||||||
|         HEAD_LOCK(); |         HEAD_LOCK(); | ||||||
|  |         tstate->prev = NULL; | ||||||
|         tstate->next = interp->tstate_head; |         tstate->next = interp->tstate_head; | ||||||
|  |         if (tstate->next) | ||||||
|  |             tstate->next->prev = tstate; | ||||||
|         interp->tstate_head = tstate; |         interp->tstate_head = tstate; | ||||||
|         HEAD_UNLOCK(); |         HEAD_UNLOCK(); | ||||||
|     } |     } | ||||||
|  | @ -349,35 +352,18 @@ static void | ||||||
| tstate_delete_common(PyThreadState *tstate) | tstate_delete_common(PyThreadState *tstate) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp; |     PyInterpreterState *interp; | ||||||
|     PyThreadState **p; |  | ||||||
|     PyThreadState *prev_p = NULL; |  | ||||||
|     if (tstate == NULL) |     if (tstate == NULL) | ||||||
|         Py_FatalError("PyThreadState_Delete: NULL tstate"); |         Py_FatalError("PyThreadState_Delete: NULL tstate"); | ||||||
|     interp = tstate->interp; |     interp = tstate->interp; | ||||||
|     if (interp == NULL) |     if (interp == NULL) | ||||||
|         Py_FatalError("PyThreadState_Delete: NULL interp"); |         Py_FatalError("PyThreadState_Delete: NULL interp"); | ||||||
|     HEAD_LOCK(); |     HEAD_LOCK(); | ||||||
|     for (p = &interp->tstate_head; ; p = &(*p)->next) { |     if (tstate->prev) | ||||||
|         if (*p == NULL) |         tstate->prev->next = tstate->next; | ||||||
|             Py_FatalError( |     else | ||||||
|                 "PyThreadState_Delete: invalid tstate"); |         interp->tstate_head = tstate->next; | ||||||
|         if (*p == tstate) |     if (tstate->next) | ||||||
|             break; |         tstate->next->prev = tstate->prev; | ||||||
|         /* 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 thread.c find_key().  */ |  | ||||||
|         if (*p == prev_p) |  | ||||||
|             Py_FatalError( |  | ||||||
|                 "PyThreadState_Delete: small circular list(!)" |  | ||||||
|                 " and tstate not found."); |  | ||||||
|         prev_p = *p; |  | ||||||
|         if ((*p)->next == interp->tstate_head) |  | ||||||
|             Py_FatalError( |  | ||||||
|                 "PyThreadState_Delete: circular list(!) and" |  | ||||||
|                 " tstate not found."); |  | ||||||
|     } |  | ||||||
|     *p = tstate->next; |  | ||||||
|     HEAD_UNLOCK(); |     HEAD_UNLOCK(); | ||||||
|     free(tstate); |     free(tstate); | ||||||
| } | } | ||||||
|  | @ -429,26 +415,16 @@ _PyThreadState_DeleteExcept(PyThreadState *tstate) | ||||||
|     HEAD_LOCK(); |     HEAD_LOCK(); | ||||||
|     /* Remove all thread states, except tstate, from the linked list of
 |     /* Remove all thread states, except tstate, from the linked list of
 | ||||||
|        thread states.  This will allow calling PyThreadState_Clear() |        thread states.  This will allow calling PyThreadState_Clear() | ||||||
|        without holding the lock. |        without holding the lock. */ | ||||||
|        XXX This would be simpler with a doubly-linked list. */ |  | ||||||
|     garbage = interp->tstate_head; |     garbage = interp->tstate_head; | ||||||
|  |     if (garbage == tstate) | ||||||
|  |         garbage = tstate->next; | ||||||
|  |     if (tstate->prev) | ||||||
|  |         tstate->prev->next = tstate->next; | ||||||
|  |     if (tstate->next) | ||||||
|  |         tstate->next->prev = tstate->prev; | ||||||
|  |     tstate->prev = tstate->next = NULL; | ||||||
|     interp->tstate_head = tstate; |     interp->tstate_head = tstate; | ||||||
|     if (garbage == tstate) { |  | ||||||
|         garbage = garbage->next; |  | ||||||
|         tstate->next = NULL; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         for (p = garbage; p; p = p->next) { |  | ||||||
|             if (p->next == tstate) { |  | ||||||
|                 p->next = tstate->next; |  | ||||||
|                 tstate->next = NULL; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     if (tstate->next != NULL) |  | ||||||
|         Py_FatalError("_PyThreadState_DeleteExcept: tstate not found " |  | ||||||
|                       "in interpreter thread states"); |  | ||||||
|     HEAD_UNLOCK(); |     HEAD_UNLOCK(); | ||||||
|     /* Clear and deallocate all stale thread states.  Even if this
 |     /* Clear and deallocate all stale thread states.  Even if this
 | ||||||
|        executes Python code, we should be safe since it executes |        executes Python code, we should be safe since it executes | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Charles-Francois Natali
						Charles-Francois Natali