📄 btthread.c
字号:
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include <kernel/OS.h>#include <support/TLS.h>#include "prlog.h"#include "primpl.h"#include "prcvar.h"#include "prpdce.h"#include <stdlib.h>#include <string.h>#include <signal.h>/* values for PRThread.state */#define BT_THREAD_PRIMORD 0x01 /* this is the primordial thread */#define BT_THREAD_SYSTEM 0x02 /* this is a system thread */#define BT_THREAD_JOINABLE 0x04 /* this is a joinable thread */struct _BT_Bookeeping{ PRLock *ml; /* a lock to protect ourselves */ sem_id cleanUpSem; /* the primoridal thread will block on this sem while waiting for the user threads */ PRInt32 threadCount; /* user thred count */} bt_book = { NULL, B_ERROR, 0 };#define BT_TPD_LIMIT 128 /* number of TPD slots we'll provide (arbitrary) *//* these will be used to map an index returned by PR_NewThreadPrivateIndex() to the corresponding beos native TLS slot number, and to the destructor for that slot - note that, because it is allocated globally, this data will be automatically zeroed for us when the program begins */static int32 tpd_beosTLSSlots[BT_TPD_LIMIT];static PRThreadPrivateDTOR tpd_dtors[BT_TPD_LIMIT];static vint32 tpd_slotsUsed=0; /* number of currently-allocated TPD slots */static int32 tls_prThreadSlot; /* TLS slot in which PRThread will be stored *//* this mutex will be used to synchronize access to every PRThread.md.joinSem and PRThread.md.is_joining (we could actually allocate one per thread, but that seems a bit excessive, especially considering that there will probably be little contention, PR_JoinThread() is allowed to block anyway, and the code protected by the mutex is short/fast) */static PRLock *joinSemLock;static PRUint32 _bt_MapNSPRToNativePriority( PRThreadPriority priority );static PRThreadPriority _bt_MapNativeToNSPRPriority( PRUint32 priority );static void _bt_CleanupThread(void *arg);static PRThread *_bt_AttachThread();void_PR_InitThreads (PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs){ PRThread *primordialThread; PRUint32 beThreadPriority; /* allocate joinSem mutex */ joinSemLock = PR_NewLock(); if (joinSemLock == NULL) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return; } /* ** Create and initialize NSPR structure for our primordial thread. */ primordialThread = PR_NEWZAP(PRThread); if( NULL == primordialThread ) { PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); return; } primordialThread->md.joinSem = B_ERROR; /* ** Set the priority to the desired level. */ beThreadPriority = _bt_MapNSPRToNativePriority( priority ); set_thread_priority( find_thread( NULL ), beThreadPriority ); primordialThread->priority = priority; /* set the thread's state - note that the thread is not joinable */ primordialThread->state |= BT_THREAD_PRIMORD; if (type == PR_SYSTEM_THREAD) primordialThread->state |= BT_THREAD_SYSTEM; /* ** Allocate a TLS slot for the PRThread structure (just using ** native TLS, as opposed to NSPR TPD, will make PR_GetCurrentThread() ** somewhat faster, and will leave one more TPD slot for our client) */ tls_prThreadSlot = tls_allocate(); /* ** Stuff our new PRThread structure into our thread specific ** slot. */ tls_set(tls_prThreadSlot, primordialThread); /* allocate lock for bt_book */ bt_book.ml = PR_NewLock(); if( NULL == bt_book.ml ) { PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); return; }}PRUint32_bt_MapNSPRToNativePriority( PRThreadPriority priority ) { switch( priority ) { case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); default: return( B_NORMAL_PRIORITY ); }}PRThreadPriority_bt_MapNativeToNSPRPriority(PRUint32 priority) { if (priority < B_NORMAL_PRIORITY) return PR_PRIORITY_LOW; if (priority < B_DISPLAY_PRIORITY) return PR_PRIORITY_NORMAL; if (priority < B_URGENT_DISPLAY_PRIORITY) return PR_PRIORITY_HIGH; return PR_PRIORITY_URGENT;}PRUint32_bt_mapNativeToNSPRPriority( int32 priority ){ switch( priority ) { case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); default: return( B_NORMAL_PRIORITY ); }}/* This method is called by all NSPR threads as they exit */void _bt_CleanupThread(void *arg){ PRThread *me = PR_GetCurrentThread(); int32 i; /* first, clean up all thread-private data */ for (i = 0; i < tpd_slotsUsed; i++) { void *oldValue = tls_get(tpd_beosTLSSlots[i]); if ( oldValue != NULL && tpd_dtors[i] != NULL ) (*tpd_dtors[i])(oldValue); } /* if this thread is joinable, wait for someone to join it */ if (me->state & BT_THREAD_JOINABLE) { /* protect access to our joinSem */ PR_Lock(joinSemLock); if (me->md.is_joining) { /* someone is already waiting to join us (they've allocated a joinSem for us) - let them know we're ready */ delete_sem(me->md.joinSem); PR_Unlock(joinSemLock); } else { /* noone is currently waiting for our demise - it is our responsibility to allocate the joinSem and block on it */ me->md.joinSem = create_sem(0, "join sem"); /* we're done accessing our joinSem */ PR_Unlock(joinSemLock); /* wait for someone to join us */ while (acquire_sem(me->md.joinSem) == B_INTERRUPTED); } } /* if this is a user thread, we must update our books */ if ((me->state & BT_THREAD_SYSTEM) == 0) { /* synchronize access to bt_book */ PR_Lock( bt_book.ml ); /* decrement the number of currently-alive user threads */ bt_book.threadCount--; if (bt_book.threadCount == 0 && bt_book.cleanUpSem != B_ERROR) { /* we are the last user thread, and the primordial thread is blocked in PR_Cleanup() waiting for us to finish - notify it */ delete_sem(bt_book.cleanUpSem); } PR_Unlock( bt_book.ml ); } /* finally, delete this thread's PRThread */ PR_DELETE(me);}/** * This is a wrapper that all threads invoke that allows us to set some * things up prior to a thread's invocation and clean up after a thread has * exited. */static void*_bt_root (void* arg) { PRThread *thred = (PRThread*)arg; PRIntn rv; void *privData; status_t result; int i; /* save our PRThread object into our TLS */ tls_set(tls_prThreadSlot, thred); thred->startFunc(thred->arg); /* run the dang thing */ /* clean up */ _bt_CleanupThread(NULL); return 0;}PR_IMPLEMENT(PRThread*) PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg, PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize){ PRUint32 bePriority; PRThread* thred; if (!_pr_initialized) _PR_ImplicitInitialization(); thred = PR_NEWZAP(PRThread); if (thred == NULL) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } thred->md.joinSem = B_ERROR; thred->arg = arg; thred->startFunc = start; thred->priority = priority; if( state == PR_JOINABLE_THREAD ) { thred->state |= BT_THREAD_JOINABLE; } /* keep some books */ PR_Lock( bt_book.ml ); if (type == PR_USER_THREAD) { bt_book.threadCount++; } PR_Unlock( bt_book.ml ); bePriority = _bt_MapNSPRToNativePriority( priority ); thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread", bePriority, thred); if (thred->md.tid < B_OK) { PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid); PR_DELETE(thred); return NULL; } if (resume_thread(thred->md.tid) < B_OK) { PR_SetError(PR_UNKNOWN_ERROR, 0); PR_DELETE(thred); return NULL; } return thred; }PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type, PRThreadPriority priority,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -