Main Page | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

threadutil.c

Go to the documentation of this file.
00001 /*!
00002  * @file threadutil.c
00003  *
00004  * @brief Utilities for operating the JVM thread state model on this
00005  * real machine implementation.
00006  *
00007  * @todo Timers for Thread.sleep() and Thread.wait() and Object.wait()
00008  * that use millisecond timers @e are supported.  The variation
00009  * that supports higher resolution of milliseconds and nanoseconds
00010  * are @e not supported, but the millisecond version is used instead.
00011  *
00012  * @internal This file also serves the dual purpose as a catch-all for
00013  * development experiments.  Due to the fact that the implementation
00014  * of the Java thread and the supporting rthread structure is deeply
00015  * embedded in the core of the development of this software, this
00016  * file has contents that come and go during development.  Some
00017  * functions get staged here before deciding where they @e really
00018  * go; some are interim functions for debugging, some were glue
00019  * that eventually went away.  Be careful to remove prototypes
00020  * to such functions from the appropriate header file.
00021  *
00022  *
00023  * @section Control
00024  *
00025  * \$URL: https://svn.apache.org/path/name/threadutil.c $ \$Id: threadutil.c 0 09/28/2005 dlydick $
00026  *
00027  * Copyright 2005 The Apache Software Foundation
00028  * or its licensors, as applicable.
00029  *
00030  * Licensed under the Apache License, Version 2.0 ("the License");
00031  * you may not use this file except in compliance with the License.
00032  * You may obtain a copy of the License at
00033  *
00034  *     http://www.apache.org/licenses/LICENSE-2.0
00035  *
00036  * Unless required by applicable law or agreed to in writing,
00037  * software distributed under the License is distributed on an
00038  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
00039  * either express or implied.
00040  *
00041  * See the License for the specific language governing permissions
00042  * and limitations under the License.
00043  *
00044  * @version \$LastChangedRevision: 0 $
00045  *
00046  * @date \$LastChangedDate: 09/28/2005 $
00047  *
00048  * @author \$LastChangedBy: dlydick $
00049  *         Original code contributed by Daniel Lydick on 09/28/2005.
00050  *
00051  * @section Reference
00052  *
00053  */
00054 
00055 #include "arch.h"
00056 ARCH_COPYRIGHT_APACHE(threadutil, c, "$URL: https://svn.apache.org/path/name/threadutil.c $ $Id: threadutil.c 0 09/28/2005 dlydick $");
00057 
00058 
00059 #include "jvmcfg.h"
00060 #include "cfmacros.h"
00061 #include "classfile.h"
00062 #include "jvm.h"
00063 #include "jvmclass.h"
00064 #include "util.h"
00065 
00066 
00067 /*!
00068  * @brief Update the interval timer for this thread from
00069  * @c @b java.lang.Thread.sleep() or from a timed
00070  * @c @b java.lang.Thread.wait() or @c @b java.lang.Thread.join().
00071  *
00072  * This function is designed to be invoked from the timeslice interrupt
00073  * handler and @e only from thence.  It DOES NOT handle
00074  * (millisec, nanosec) resolution, only millisecond resolution.
00075  *
00076  *
00077  * @b Parameters: @link #rvoid rvoid@endlink
00078  *
00079  *
00080  *       @returns @link #rvoid rvoid@endlink
00081  *
00082  */
00083 
00084 rvoid threadutil_update_sleeptime_interval(rvoid)
00085 {
00086     jvm_thread_index thridx;
00087 
00088     /* Lock out the @e world during timer update */
00089     pthread_mutex_lock(&pjvm->sleeplock);
00090 
00091     for (thridx = jvm_thread_index_null;
00092          thridx < JVMCFG_MAX_THREADS;
00093          thridx++)
00094     {
00095         if ((THREAD_STATUS_INUSE    & THREAD(thridx).status)    &&
00096             ((THREAD_STATUS_SLEEP     |
00097               THREAD_STATUS_JOINTIMED |
00098               THREAD_STATUS_WAITTIMED  ) & THREAD(thridx).status))
00099         {
00100             /*
00101              * Perform next interval update.  Stop decrementing
00102              * when time reaches zero.
00103              */
00104             if (0 != THREAD(thridx).sleeptime)
00105             {
00106                 THREAD(thridx).sleeptime--;
00107             }
00108         }
00109     }
00110 
00111     /* Unlock the @e world after timer update */
00112     pthread_mutex_unlock(&pjvm->sleeplock);
00113 
00114     return;
00115 
00116 } /* END of threadutil_update_sleeptime_interval() */
00117 
00118 
00119 /*!
00120  * @brief Complete the UNtimed Thread.join() request and allow threads
00121  * that have joined this one to resume execution.
00122  *
00123  * This function is typically called when a thread enters the
00124  * @b COMPLETE state after finishing its JVM execution.
00125  *
00126  * Review state of thread table, looking for the following conditions.
00127  * For those that meet them, move thread out of given state and
00128  * forward to next state.  Three functions are used, depending on
00129  * the current state, threadutil_update_blockingevent() and
00130  * threadutil_update_wait() and threadutil_update_lock():
00131  *
00132  * @verbatim
00133 
00134    Condition:         Current state: Next state:  threadutil_update_YYY:
00135    ----------         -------------- -----------  ----------------------
00136   
00137    Thread.join()      COMPLETE       N/C              _blockingevents()
00138    (forever, where
00139    current thread
00140    is COMPLETE, and
00141    target thread is
00142    BLOCKED, and is
00143    moved to UNBLOCKED)
00144   
00145    Thread.join(n)     COMPLETE       N/C              _blockingevents()
00146    (timed, where
00147    n has expired
00148    on current
00149    thread or it is
00150    COMPLETE, and
00151    target thread
00152    is BLOCKED, and
00153    is moved to
00154    UNBLOCKED)
00155   
00156    Thread.sleep(n)    BLOCKED        UNBLOCKED        _blockingevents()
00157    (n has expired on
00158    current thread)
00159   
00160    Interruptible I/O  BLOCKED        UNBLOCKED        _blockingevents()
00161    from class
00162    java.nio.channels
00163    .InterruptibleChannel
00164   
00165    Object.wait()      WAIT           NOTIFY           _wait()
00166    (forever on
00167    current thread,
00168    where target object
00169    lock was released)
00170   
00171    Object.wait(n)     WAIT           NOTIFY           _wait()
00172    (timed, where
00173    @c @b n
00174    has expired on
00175    current thread
00176    or target object
00177    lock was released)
00178   
00179    One of:            LOCK           ACQUIRE          _lock()
00180    Object.notify()
00181    Object.notifyAll()
00182    Thread.interrupt()
00183    synchronized(Object)
00184    ... put thread
00185    into LOCK state.
00186    Now it will
00187    negotiate to
00188    ACQUIRE its
00189    object's
00190    monitor lock.
00191    
00192   
00193    Thread.suspend()   ANY            BLOCKED        threadutil_suspend()
00194   
00195    Thread.resume()    BLOCKED        UNBLOCKED       threadutil_resume()
00196    moves a
00197    Thread.suspend()
00198    thread forward
00199    to UNBLOCKED
00200   
00201    @endverbatim
00202  *
00203  * With the exception of threadutil_suspend() and threadutil_resume(),
00204  * these functions is designed to be invoked from the JVM outer loop.
00205  * CAVEAT EMPTOR:  Those two functions are deprecated.  Use
00206  * at your own risk!
00207  *
00208  * @todo Interruptible from class
00209  * @c @b java.nio.channels.InterruptibleChannel
00210  *
00211  *
00212  * @param  thridxcurr   Thread for which to examine state changes
00213  *
00214  *
00215  * @returns @link #rvoid rvoid@endlink
00216  *
00217  */
00218 
00219 rvoid threadutil_update_blockingevents(jvm_thread_index thridxcurr)
00220 {
00221     /* Only examine INUSE threads in selected states */
00222     if (!(THREAD_STATUS_INUSE & THREAD(thridxcurr).status))
00223     {
00224         return;
00225     }
00226 
00227     switch (THREAD(thridxcurr).this_state)
00228     {
00229         case THREAD_STATE_COMPLETE:  /* Untimed/untimed Thread.join() */
00230 
00231         case THREAD_STATE_BLOCKED:   /* Thread.sleep() and */
00232                                      /*! @todo interruptible I/O req's*/
00233 
00234         default:                     /* Not meaningful for this logic */
00235             return;
00236     }
00237 
00238     /* sleep() -- time period expired for only this thread */
00239     if ((THREAD_STATE_BLOCKED == THREAD(thridxcurr).this_state) &&
00240        (THREAD_STATUS_SLEEP   &  THREAD(thridxcurr).status)     &&
00241        (0 == timeslice_get_thread_sleeptime(thridxcurr)))
00242     {
00243         /* Mark thread to continue now after sleep() */
00244         THREAD(thridxcurr).status &= ~THREAD_STATUS_SLEEP;
00245         threadstate_request_unblocked(thridxcurr);
00246 
00247         /*
00248          * Check if Thread.interrupt() was thrown
00249          * against this thread.
00250          *
00251          * Also need to throw the exception in JVM outer loop.
00252          */
00253         if (THREAD_STATUS_INTERRUPTED & THREAD(thridxcurr).status)
00254         {
00255             THREAD(thridxcurr).status &= ~THREAD_STATUS_INTERRUPTED;
00256 
00257             THREAD(thridxcurr).status |= THREAD_STATUS_THREW_EXCEPTION;
00258 
00259             THREAD(thridxcurr).pThrowableEvent =
00260                                 JVMCLASS_JAVA_LANG_INTERRUPTEDEXCEPTION;
00261         }
00262     }
00263     else
00264 
00265     /*! @todo  First pass guess at interruptible I/O */
00266     if ((THREAD_STATE_BLOCKED == THREAD(thridxcurr).this_state) &&
00267         (THREAD_STATUS_INTERRUPTIBLEIO & THREAD(thridxcurr).status))
00268     {
00269         /*!
00270          * Check if Thread.interrupt() was thrown
00271          * against the interruptible I/O operation on this thread.
00272          *
00273          * @todo Is this the correct way to handle
00274          *       interruptible I/O events?
00275          *       Also need to throw the exception in JVM outer loop.
00276          */
00277         if (THREAD_STATUS_INTERRUPTED & THREAD(thridxcurr).status)
00278         {
00279             /* Mark thread to continue now after Thread.interrupt() */
00280             THREAD(thridxcurr).status &= ~THREAD_STATUS_INTERRUPTIBLEIO;
00281             threadstate_request_unblocked(thridxcurr);
00282 
00283             THREAD(thridxcurr).status &= ~THREAD_STATUS_INTERRUPTED;
00284 
00285             THREAD(thridxcurr).status |= THREAD_STATUS_THREW_EXCEPTION;
00286 
00287             THREAD(thridxcurr).pThrowableEvent =
00288                 JVMCLASS_JAVA_NIO_CHANNELS_CLOSEDBYINTERRUPTEXCEPTION;
00289         }
00290     }
00291     else
00292 
00293     /*
00294      * Examine Thread.join() conditions, both timed and untimed
00295      */
00296     if (THREAD_STATE_COMPLETE == THREAD(thridxcurr).this_state)
00297     {
00298         jvm_thread_index thridxjoin;
00299 
00300                   /* Skip JVMCFG_NULL_THREAD */
00301         for (thridxjoin = JVMCFG_SYSTEM_THREAD;
00302              thridxjoin < JVMCFG_MAX_THREADS;
00303              thridxjoin++)
00304         {
00305             /*
00306              * Skip myself
00307              */
00308             if (thridxcurr == thridxjoin)
00309             {
00310                 continue;
00311             }
00312 
00313             /* Only process threads in the BLOCKED state */
00314             if (THREAD_STATE_BLOCKED != THREAD(thridxjoin).this_state)
00315             {
00316                 continue; 
00317             }
00318 
00319             /*
00320              * If current COMPLETE thread is the target of a join,
00321              * check which type it is, timed or untimed.
00322              */
00323             if (thridxcurr == THREAD(thridxjoin).jointarget)
00324             {
00325                 /* UNtimed join() -- where time period is zero/forever*/
00326                 if ((THREAD_STATUS_JOIN4EVER &
00327                      THREAD(thridxjoin).status))
00328                 {
00329                     /* Mark joined thread to be UNBLOCKED after join()*/
00330                     THREAD(thridxjoin).jointarget =
00331                                                   jvm_thread_index_null;
00332                     THREAD(thridxjoin).status &= 
00333                                                ~THREAD_STATUS_JOIN4EVER;
00334                     threadstate_request_unblocked(thridxjoin);
00335 
00336                     /*
00337                      * Check if Thread.interrupted() was thrown
00338                      * against this thread.
00339                      */
00340                     if (THREAD_STATUS_INTERRUPTED &
00341                         THREAD(thridxjoin).status)
00342                     {
00343                         THREAD(thridxjoin).status &=
00344                                              ~THREAD_STATUS_INTERRUPTED;
00345 
00346                         THREAD(thridxjoin).status |=
00347                                           THREAD_STATUS_THREW_EXCEPTION;
00348 
00349                         THREAD(thridxjoin).pThrowableEvent =
00350                             JVMCLASS_JAVA_LANG_INTERRUPTEDEXCEPTION;
00351                     }
00352 
00353                 }
00354                 else
00355 
00356                 /* TIMED join() --time period is NON-zero,now expired */
00357                 if ((THREAD_STATUS_JOINTIMED &
00358                                      THREAD(thridxjoin).status) &&
00359                     (0 == timeslice_get_thread_sleeptime(thridxjoin)))
00360                 {
00361                     /* Mark joined thread to be UNBLOCKED after join()*/
00362                     THREAD(thridxjoin).jointarget =
00363                                                   jvm_thread_index_null;
00364                     THREAD(thridxjoin).status &=
00365                                                ~THREAD_STATUS_JOINTIMED;
00366                     threadstate_request_unblocked(thridxjoin);
00367 
00368                     /*
00369                      * Check if Thread.interrupted() was thrown
00370                      * against this thread.
00371                      */
00372                     if (THREAD_STATUS_INTERRUPTED &
00373                         THREAD(thridxjoin).status)
00374                     {
00375                         THREAD(thridxjoin).status &=
00376                                              ~THREAD_STATUS_INTERRUPTED;
00377 
00378                         THREAD(thridxjoin).status |=
00379                             THREAD_STATUS_THREW_EXCEPTION;
00380 
00381                         THREAD(thridxjoin).pThrowableEvent =
00382                             JVMCLASS_JAVA_LANG_INTERRUPTEDEXCEPTION;
00383                     }
00384                 }
00385             }
00386         }
00387     }
00388 
00389     return;
00390 
00391 } /* END of threadutil_update_blockingevents() */
00392 
00393 
00394 rvoid threadutil_update_wait(jvm_thread_index thridxcurr)
00395 {
00396     /* Only examine INUSE threads in WAIT state */
00397     if (!(THREAD_STATUS_INUSE & THREAD(thridxcurr).status))
00398     {
00399         return;
00400     }
00401 
00402     switch (THREAD(thridxcurr).this_state)
00403     {
00404         case THREAD_STATE_WAIT:      /* Timed/untimed Object.wait() */
00405             break;
00406 
00407         default:                     /* Not meaningful for this logic */
00408             return;
00409     }
00410 
00411 
00412     /* wait() -- Check for notify() or notifyAll() or interrupt() */
00413     if (THREAD_STATUS_WAIT4EVER & THREAD(thridxcurr).status)
00414     {
00415         /*
00416          * Check if Thread.interrupt() was thrown against this thread
00417          * or if Object.notify() against this object by this thread.
00418          *
00419          * (Also need to throw the exception in JVM outer loop.)
00420          */
00421         if (THREAD_STATUS_INTERRUPTED & THREAD(thridxcurr).status)
00422         {
00423             THREAD(thridxcurr).status &= ~THREAD_STATUS_INTERRUPTED;
00424 
00425             THREAD(thridxcurr).status |= THREAD_STATUS_THREW_EXCEPTION;
00426 
00427             THREAD(thridxcurr).pThrowableEvent =
00428                                 JVMCLASS_JAVA_LANG_INTERRUPTEDEXCEPTION;
00429 
00430             /* Remove WAIT condition and move to NOTIFY state */
00431             THREAD(thridxcurr).status &= ~THREAD_STATUS_WAIT4EVER;
00432             threadstate_request_notify(thridxcurr);
00433         }
00434         else
00435         if (THREAD_STATUS_NOTIFIED & THREAD(thridxcurr).status)
00436         {
00437             THREAD(thridxcurr).status &= ~THREAD_STATUS_NOTIFIED;
00438 
00439             /* Remove WAIT condition and move to NOTIFY state */
00440             THREAD(thridxcurr).status &= ~THREAD_STATUS_WAIT4EVER;
00441             threadstate_request_notify(thridxcurr);
00442         }
00443     }
00444     else
00445 
00446     /* wait(n) -- TIMED, chk if monitor lock released on target object
00447                   or if timer expired */
00448     if ((THREAD_STATUS_WAITTIMED &  THREAD(thridxcurr).status)   &&
00449         (jvm_object_hash_null    != THREAD(thridxcurr).locktarget))
00450     {
00451         /* Give up if timer expired */
00452         if (0 == timeslice_get_thread_sleeptime(thridxcurr))
00453         {
00454             /* Remove @b WAIT condition and move to next state */
00455             THREAD(thridxcurr).status &= ~THREAD_STATUS_WAITTIMED;
00456             threadstate_request_notify(thridxcurr);
00457         }
00458         else
00459         {
00460             /*
00461              * Check if Thread.interrupt() was thrown against this
00462              * thread or if Object.notify() against this object by this
00463              * thread.
00464              *
00465              * (Also need to throw the exception in JVM outer loop.)
00466              */
00467             if (THREAD_STATUS_INTERRUPTED & THREAD(thridxcurr).status)
00468             {
00469                 THREAD(thridxcurr).status &= ~THREAD_STATUS_INTERRUPTED;
00470 
00471                 THREAD(thridxcurr).status |=
00472                                           THREAD_STATUS_THREW_EXCEPTION;
00473 
00474                 THREAD(thridxcurr).pThrowableEvent =
00475                                 JVMCLASS_JAVA_LANG_INTERRUPTEDEXCEPTION;
00476 
00477                 /* Remove WAIT condition and move to NOTIFY state */
00478                 THREAD(thridxcurr).status &= ~THREAD_STATUS_WAITTIMED;
00479                 threadstate_request_notify(thridxcurr);
00480             }
00481             else
00482             if (THREAD_STATUS_NOTIFIED & THREAD(thridxcurr).status)
00483             {
00484                 THREAD(thridxcurr).status &= ~THREAD_STATUS_NOTIFIED;
00485 
00486                 /* Remove WAIT condition and move to NOTIFY state */
00487                 THREAD(thridxcurr).status &= ~THREAD_STATUS_WAITTIMED;
00488                 threadstate_request_notify(thridxcurr);
00489             }
00490         }
00491     }
00492 
00493     return;
00494 
00495 } /* END of threadutil_update_wait() */
00496 
00497 
00498 rvoid threadutil_update_lock(jvm_thread_index thridxcurr)
00499 {
00500     /* Only examine INUSE threads in LOCK state */
00501     if (!(THREAD_STATUS_INUSE & THREAD(thridxcurr).status))
00502     {
00503         return;
00504     }
00505 
00506     switch (THREAD(thridxcurr).this_state)
00507     {
00508         case THREAD_STATE_LOCK:      /* Lock arbitration */
00509             break;
00510 
00511         default:                     /* Not meaningful for this logic */
00512             return;
00513     }
00514 
00515 
00516     /*
00517      * One of java.lang.Object.notify() or java.lang.Object.notifyAll()
00518      * or java.lang.Thread.interrupt() or a @c @b synchronize()
00519      * block got the thread here, now try to wake up from @b LOCK with
00520      * the target object's monitor lock acquired, if currently
00521      * available.
00522      *
00523      * To do so, check if previous thread unlocked this object.  If so,
00524      * go lock it for use by this thread.
00525      */
00526     if ((jvm_object_hash_null != THREAD(thridxcurr).locktarget) &&
00527         (!(OBJECT_STATUS_MLOCK & OBJECT(THREAD(thridxcurr).locktarget)
00528                                    .status)))
00529     {
00530         /* If fail, arbitrate here again next time around */
00531         if (rtrue ==
00532             objectutil_synchronize(THREAD(thridxcurr).locktarget,
00533                                    thridxcurr))
00534         {
00535             /* Move to @b ACQUIRE state */
00536             THREAD(thridxcurr).status &= ~THREAD_STATUS_WAIT4EVER;
00537             threadstate_request_acquire(thridxcurr);
00538         }
00539     }
00540 
00541     return;
00542 
00543 } /* END of threadutil_update_lock() */
00544 
00545 
00546 /*!
00547  * @brief Examine an object to see if a thread owns its monitor lock
00548  *
00549  *
00550  * @param thridx      Thread table index of thread to compare with.
00551  *
00552  * @param objhashlock Object table hash of object to examine.
00553  *
00554  *
00555  * @returns @link #rtrue rtrue@endlink if this thread owns
00556  *          this object's monitor lock.
00557  *
00558  */
00559 
00560 rboolean threadutil_holds_lock(jvm_thread_index thridx,
00561                                jvm_object_hash  objhashlock)
00562 {
00563     /*
00564      * Make sure thread and object are both in use,
00565      * make sure object is locked, then do @b BIDIRECTIONAL check
00566      * to see if object and thread think each other is in sync
00567      * and that @e this thread indeed @b DOES hold the lock on @e this
00568      * object.
00569      */
00570 
00571     /* Prerequisite to this check */
00572     if ((!(OBJECT_STATUS_INUSE & OBJECT(objhashlock).status)) ||
00573         (OBJECT_STATUS_NULL    & OBJECT(objhashlock).status))
00574     {
00575         return(rfalse);
00576     }
00577 
00578     /* Prerequisite to this check */
00579     if ((!(THREAD_STATUS_INUSE & THREAD(thridx).status)) ||
00580         (THREAD_STATUS_NULL    & THREAD(thridx).status))
00581     {
00582         return(rfalse);
00583     }
00584 
00585     if ((OBJECT_STATUS_MLOCK & OBJECT(objhashlock).status) &&
00586         (thridx             == OBJECT(objhashlock).mlock_thridx)  &&
00587         ((THREAD_STATUS_WAIT4EVER |
00588           THREAD_STATUS_WAITTIMED ) & THREAD(thridx).status) &&
00589         (objhashlock        == THREAD(thridx).locktarget))
00590     {
00591         return(rtrue);
00592     }
00593 
00594     return(rfalse);
00595 
00596 } /* END of threadutil_holds_lock() */
00597 
00598 
00599 /* EOF */
00600 

Generated on Fri Sep 30 18:49:09 2005 by  doxygen 1.4.4