Back to index

lightning-sunbird  0.9+nobinonly
pthreads_user.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 #include <sys/types.h>
00040 #include <unistd.h>
00041 #include <signal.h>
00042 #include <pthread.h>
00043 
00044 
00045 sigset_t ints_off;
00046 pthread_mutex_t      _pr_heapLock;
00047 pthread_key_t current_thread_key;
00048 pthread_key_t current_cpu_key;
00049 pthread_key_t last_thread_key;
00050 pthread_key_t intsoff_key;
00051 
00052 
00053 PRInt32 _pr_md_pthreads_created, _pr_md_pthreads_failed;
00054 PRInt32 _pr_md_pthreads = 1;
00055 
00056 void _MD_EarlyInit(void)
00057 {
00058 extern PRInt32 _nspr_noclock;
00059 
00060        if (pthread_key_create(&current_thread_key, NULL) != 0) {
00061               perror("pthread_key_create failed");
00062               exit(1);
00063        }
00064        if (pthread_key_create(&current_cpu_key, NULL) != 0) {
00065               perror("pthread_key_create failed");
00066               exit(1);
00067        }
00068        if (pthread_key_create(&last_thread_key, NULL) != 0) {
00069               perror("pthread_key_create failed");
00070               exit(1);
00071        }
00072        if (pthread_key_create(&intsoff_key, NULL) != 0) {
00073               perror("pthread_key_create failed");
00074               exit(1);
00075        }
00076 
00077        sigemptyset(&ints_off);
00078        sigaddset(&ints_off, SIGALRM);
00079        sigaddset(&ints_off, SIGIO);
00080        sigaddset(&ints_off, SIGCLD);
00081 
00082        /*
00083         * disable clock interrupts
00084         */
00085        _nspr_noclock = 1;
00086 
00087 }
00088 
00089 void _MD_InitLocks()
00090 {
00091        if (pthread_mutex_init(&_pr_heapLock, NULL) != 0) {
00092               perror("pthread_mutex_init failed");
00093               exit(1);
00094        }
00095 }
00096 
00097 PR_IMPLEMENT(void) _MD_FREE_LOCK(struct _MDLock *lockp)
00098 {
00099        PRIntn _is;
00100        PRThread *me = _PR_MD_CURRENT_THREAD();
00101 
00102        if (me && !_PR_IS_NATIVE_THREAD(me))
00103               _PR_INTSOFF(_is); 
00104        pthread_mutex_destroy(&lockp->mutex);
00105        if (me && !_PR_IS_NATIVE_THREAD(me))
00106               _PR_FAST_INTSON(_is);
00107 }
00108 
00109 
00110 
00111 PR_IMPLEMENT(PRStatus) _MD_NEW_LOCK(struct _MDLock *lockp)
00112 {
00113     PRStatus rv;
00114     PRIntn is;
00115     PRThread *me = _PR_MD_CURRENT_THREAD();      
00116 
00117        if (me && !_PR_IS_NATIVE_THREAD(me))
00118               _PR_INTSOFF(is);
00119        rv = pthread_mutex_init(&lockp->mutex, NULL);
00120        if (me && !_PR_IS_NATIVE_THREAD(me))
00121               _PR_FAST_INTSON(is);
00122        return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
00123 }
00124 
00125 
00126 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
00127 {
00128     if (isCurrent) {
00129        (void) setjmp(CONTEXT(t));
00130     }
00131     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
00132     return (PRWord *) CONTEXT(t);
00133 }
00134 
00135 PR_IMPLEMENT(void)
00136 _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri)
00137 {
00138        /*
00139         * XXX - to be implemented
00140         */
00141     return;
00142 }
00143 
00144 PR_IMPLEMENT(PRStatus) _MD_InitThread(struct PRThread *thread)
00145 {
00146     struct sigaction sigact;
00147 
00148     if (thread->flags & _PR_GLOBAL_SCOPE) {
00149         thread->md.pthread = pthread_self();
00150 #if 0
00151               /*
00152                * set up SIGUSR1 handler; this is used to save state
00153                * during PR_SuspendAll
00154                */
00155               sigact.sa_handler = save_context_and_block;
00156               sigact.sa_flags = SA_RESTART;
00157               /*
00158                * Must mask clock interrupts
00159                */
00160               sigact.sa_mask = timer_set;
00161               sigaction(SIGUSR1, &sigact, 0);
00162 #endif
00163     }
00164 
00165     return PR_SUCCESS;
00166 }
00167 
00168 PR_IMPLEMENT(void) _MD_ExitThread(struct PRThread *thread)
00169 {
00170     if (thread->flags & _PR_GLOBAL_SCOPE) {
00171         _MD_CLEAN_THREAD(thread);
00172         _MD_SET_CURRENT_THREAD(NULL);
00173     }
00174 }
00175 
00176 PR_IMPLEMENT(void) _MD_CleanThread(struct PRThread *thread)
00177 {
00178     if (thread->flags & _PR_GLOBAL_SCOPE) {
00179               pthread_mutex_destroy(&thread->md.pthread_mutex);
00180               pthread_cond_destroy(&thread->md.pthread_cond);
00181     }
00182 }
00183 
00184 PR_IMPLEMENT(void) _MD_SuspendThread(struct PRThread *thread)
00185 {
00186     PRInt32 rv;
00187 
00188     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
00189         _PR_IS_GCABLE_THREAD(thread));
00190 #if 0
00191        thread->md.suspending_id = getpid();
00192        rv = kill(thread->md.id, SIGUSR1);
00193        PR_ASSERT(rv == 0);
00194        /*
00195         * now, block the current thread/cpu until woken up by the suspended
00196         * thread from it's SIGUSR1 signal handler
00197         */
00198        blockproc(getpid());
00199 #endif
00200 }
00201 
00202 PR_IMPLEMENT(void) _MD_ResumeThread(struct PRThread *thread)
00203 {
00204     PRInt32 rv;
00205 
00206     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
00207         _PR_IS_GCABLE_THREAD(thread));
00208 #if 0
00209     rv = unblockproc(thread->md.id);
00210 #endif
00211 }
00212 
00213 PR_IMPLEMENT(void) _MD_SuspendCPU(struct _PRCPU *thread)
00214 {
00215     PRInt32 rv;
00216 
00217 #if 0
00218        cpu->md.suspending_id = getpid();
00219        rv = kill(cpu->md.id, SIGUSR1);
00220        PR_ASSERT(rv == 0);
00221        /*
00222         * now, block the current thread/cpu until woken up by the suspended
00223         * thread from it's SIGUSR1 signal handler
00224         */
00225        blockproc(getpid());
00226 #endif
00227 }
00228 
00229 PR_IMPLEMENT(void) _MD_ResumeCPU(struct _PRCPU *thread)
00230 {
00231 #if 0
00232        unblockproc(cpu->md.id);
00233 #endif
00234 }
00235 
00236 
00237 #define PT_NANOPERMICRO 1000UL
00238 #define PT_BILLION 1000000000UL
00239 
00240 PR_IMPLEMENT(PRStatus)
00241 _pt_wait(PRThread *thread, PRIntervalTime timeout)
00242 {
00243 int rv;
00244 struct timeval now;
00245 struct timespec tmo;
00246 PRUint32 ticks = PR_TicksPerSecond();
00247 
00248 
00249        if (timeout != PR_INTERVAL_NO_TIMEOUT) {
00250               tmo.tv_sec = timeout / ticks;
00251               tmo.tv_nsec = timeout - (tmo.tv_sec * ticks);
00252               tmo.tv_nsec = PR_IntervalToMicroseconds(PT_NANOPERMICRO *
00253                                                                              tmo.tv_nsec);
00254 
00255               /* pthreads wants this in absolute time, off we go ... */
00256               (void)GETTIMEOFDAY(&now);
00257               /* that one's usecs, this one's nsecs - grrrr! */
00258               tmo.tv_sec += now.tv_sec;
00259               tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
00260               tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
00261               tmo.tv_nsec %= PT_BILLION;
00262        }
00263 
00264        pthread_mutex_lock(&thread->md.pthread_mutex);
00265        thread->md.wait--;
00266        if (thread->md.wait < 0) {
00267               if (timeout != PR_INTERVAL_NO_TIMEOUT) {
00268                      rv = pthread_cond_timedwait(&thread->md.pthread_cond,
00269                                    &thread->md.pthread_mutex, &tmo);
00270         }
00271               else
00272                      rv = pthread_cond_wait(&thread->md.pthread_cond,
00273                                    &thread->md.pthread_mutex);
00274               if (rv != 0) {
00275                      thread->md.wait++;
00276               }
00277        } else
00278               rv = 0;
00279        pthread_mutex_unlock(&thread->md.pthread_mutex);
00280 
00281        return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
00282 }
00283 
00284 PR_IMPLEMENT(PRStatus)
00285 _MD_wait(PRThread *thread, PRIntervalTime ticks)
00286 {
00287     if ( thread->flags & _PR_GLOBAL_SCOPE ) {
00288               _MD_CHECK_FOR_EXIT();
00289         if (_pt_wait(thread, ticks) == PR_FAILURE) {
00290               _MD_CHECK_FOR_EXIT();
00291             /*
00292              * wait timed out
00293              */
00294             _PR_THREAD_LOCK(thread);
00295             if (thread->wait.cvar) {
00296                 /*
00297                  * The thread will remove itself from the waitQ
00298                  * of the cvar in _PR_WaitCondVar
00299                  */
00300                 thread->wait.cvar = NULL;
00301                 thread->state =  _PR_RUNNING;
00302                 _PR_THREAD_UNLOCK(thread);
00303             }  else {
00304                      _pt_wait(thread, PR_INTERVAL_NO_TIMEOUT);
00305                 _PR_THREAD_UNLOCK(thread);
00306             }
00307         }
00308     } else {
00309               _PR_MD_SWITCH_CONTEXT(thread);
00310     }
00311     return PR_SUCCESS;
00312 }
00313 
00314 PR_IMPLEMENT(PRStatus)
00315 _MD_WakeupWaiter(PRThread *thread)
00316 {
00317     PRThread *me = _PR_MD_CURRENT_THREAD();
00318     PRInt32 pid, rv;
00319     PRIntn is;
00320 
00321        PR_ASSERT(_pr_md_idle_cpus >= 0);
00322     if (thread == NULL) {
00323               if (_pr_md_idle_cpus)
00324               _MD_Wakeup_CPUs();
00325     } else if (!_PR_IS_NATIVE_THREAD(thread)) {
00326               /*
00327                * If the thread is on my cpu's runq there is no need to
00328                * wakeup any cpus
00329                */
00330               if (!_PR_IS_NATIVE_THREAD(me)) {
00331                      if (me->cpu != thread->cpu) {
00332                             if (_pr_md_idle_cpus)
00333                             _MD_Wakeup_CPUs();
00334                      }
00335               } else {
00336                      if (_pr_md_idle_cpus)
00337                      _MD_Wakeup_CPUs();
00338               }
00339     } else {
00340               PR_ASSERT(_PR_IS_NATIVE_THREAD(thread));
00341               if (!_PR_IS_NATIVE_THREAD(me))
00342                      _PR_INTSOFF(is);
00343 
00344               pthread_mutex_lock(&thread->md.pthread_mutex);
00345               thread->md.wait++;
00346               rv = pthread_cond_signal(&thread->md.pthread_cond);
00347               PR_ASSERT(rv == 0);
00348               pthread_mutex_unlock(&thread->md.pthread_mutex);
00349 
00350               if (!_PR_IS_NATIVE_THREAD(me))
00351                      _PR_FAST_INTSON(is);
00352     } 
00353     return PR_SUCCESS;
00354 }
00355 
00356 /* These functions should not be called for AIX */
00357 PR_IMPLEMENT(void)
00358 _MD_YIELD(void)
00359 {
00360     PR_NOT_REACHED("_MD_YIELD should not be called for AIX.");
00361 }
00362 
00363 PR_IMPLEMENT(PRStatus)
00364 _MD_CreateThread(
00365     PRThread *thread,
00366     void (*start) (void *),
00367     PRThreadPriority priority,
00368     PRThreadScope scope,
00369     PRThreadState state,
00370     PRUint32 stackSize)
00371 {
00372     PRIntn is;
00373     int rv;
00374        PRThread *me = _PR_MD_CURRENT_THREAD();   
00375        pthread_attr_t attr;
00376 
00377        if (!_PR_IS_NATIVE_THREAD(me))
00378               _PR_INTSOFF(is);
00379 
00380        if (pthread_mutex_init(&thread->md.pthread_mutex, NULL) != 0) {
00381               if (!_PR_IS_NATIVE_THREAD(me))
00382                      _PR_FAST_INTSON(is);
00383         return PR_FAILURE;
00384        }
00385 
00386        if (pthread_cond_init(&thread->md.pthread_cond, NULL) != 0) {
00387               pthread_mutex_destroy(&thread->md.pthread_mutex);
00388               if (!_PR_IS_NATIVE_THREAD(me))
00389                      _PR_FAST_INTSON(is);
00390         return PR_FAILURE;
00391        }
00392     thread->flags |= _PR_GLOBAL_SCOPE;
00393 
00394        pthread_attr_init(&attr); /* initialize attr with default attributes */
00395        if (pthread_attr_setstacksize(&attr, (size_t) stackSize) != 0) {
00396               pthread_mutex_destroy(&thread->md.pthread_mutex);
00397               pthread_cond_destroy(&thread->md.pthread_cond);
00398               pthread_attr_destroy(&attr);
00399               if (!_PR_IS_NATIVE_THREAD(me))
00400                      _PR_FAST_INTSON(is);
00401         return PR_FAILURE;
00402        }
00403 
00404        thread->md.wait = 0;
00405     rv = pthread_create(&thread->md.pthread, &attr, start, (void *)thread);
00406     if (0 == rv) {
00407         _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_created);
00408         _MD_ATOMIC_INCREMENT(&_pr_md_pthreads);
00409               if (!_PR_IS_NATIVE_THREAD(me))
00410                      _PR_FAST_INTSON(is);
00411         return PR_SUCCESS;
00412     } else {
00413               pthread_mutex_destroy(&thread->md.pthread_mutex);
00414               pthread_cond_destroy(&thread->md.pthread_cond);
00415               pthread_attr_destroy(&attr);
00416         _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_failed);
00417               if (!_PR_IS_NATIVE_THREAD(me))
00418                      _PR_FAST_INTSON(is);
00419         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, rv);
00420         return PR_FAILURE;
00421     }
00422 }
00423 
00424 PR_IMPLEMENT(void)
00425 _MD_InitRunningCPU(struct _PRCPU *cpu)
00426 {
00427     extern int _pr_md_pipefd[2];
00428 
00429     _MD_unix_init_running_cpu(cpu);
00430     cpu->md.pthread = pthread_self();
00431        if (_pr_md_pipefd[0] >= 0) {
00432        _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0];
00433 #ifndef _PR_USE_POLL
00434        FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu));
00435 #endif
00436        }
00437 }
00438 
00439 
00440 void
00441 _MD_CleanupBeforeExit(void)
00442 {
00443 #if 0
00444     extern PRInt32    _pr_cpus_exit;
00445 
00446        _pr_irix_exit_now = 1;
00447     if (_pr_numCPU > 1) {
00448         /*
00449          * Set a global flag, and wakeup all cpus which will notice the flag
00450          * and exit.
00451          */
00452         _pr_cpus_exit = getpid();
00453         _MD_Wakeup_CPUs();
00454         while(_pr_numCPU > 1) {
00455             _PR_WAIT_SEM(_pr_irix_exit_sem);
00456             _pr_numCPU--;
00457         }
00458     }
00459     /*
00460      * cause global threads on the recycle list to exit
00461      */
00462      _PR_DEADQ_LOCK;
00463      if (_PR_NUM_DEADNATIVE != 0) {
00464        PRThread *thread;
00465        PRCList *ptr;
00466 
00467         ptr = _PR_DEADNATIVEQ.next;
00468         while( ptr != &_PR_DEADNATIVEQ ) {
00469               thread = _PR_THREAD_PTR(ptr);
00470               _MD_CVAR_POST_SEM(thread);
00471                 ptr = ptr->next;
00472         } 
00473      }
00474      _PR_DEADQ_UNLOCK;
00475      while(_PR_NUM_DEADNATIVE > 1) {
00476        _PR_WAIT_SEM(_pr_irix_exit_sem);
00477        _PR_DEC_DEADNATIVE;
00478      }
00479 #endif
00480 }