00001 /*! 00002 * @file timeslice.c 00003 * 00004 * @brief JVM one millisecond time slice timer. 00005 * 00006 * The @link rjvm.timeslice_expired pjvm->timeslice_expired@endlink 00007 * flag is set by the periodic @b SIGALRM herein and tested in the JVM 00008 * virtual instruction inner loop to decide when a thread has finished 00009 * using its time slice. 00010 * 00011 * @verbatim 00012 function flag value meaning 00013 -------- ---------- ------- 00014 00015 timeslice_init() set rfalse initial value 00016 00017 timeslice_tick() set rtrue time slice finished 00018 00019 jvm_run() rfalse keep running this slice 00020 rtrue time slice finished 00021 @endverbatim 00022 * 00023 * 00024 * @section Control 00025 * 00026 * \$URL: https://svn.apache.org/path/name/timeslice.c $ \$Id: timeslice.c 0 09/28/2005 dlydick $ 00027 * 00028 * Copyright 2005 The Apache Software Foundation 00029 * or its licensors, as applicable. 00030 * 00031 * Licensed under the Apache License, Version 2.0 ("the License"); 00032 * you may not use this file except in compliance with the License. 00033 * You may obtain a copy of the License at 00034 * 00035 * http://www.apache.org/licenses/LICENSE-2.0 00036 * 00037 * Unless required by applicable law or agreed to in writing, 00038 * software distributed under the License is distributed on an 00039 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 00040 * either express or implied. 00041 * 00042 * See the License for the specific language governing permissions 00043 * and limitations under the License. 00044 * 00045 * @version \$LastChangedRevision: 0 $ 00046 * 00047 * @date \$LastChangedDate: 09/28/2005 $ 00048 * 00049 * @author \$LastChangedBy: dlydick $ 00050 * Original code contributed by Daniel Lydick on 09/28/2005. 00051 * 00052 * @section Reference 00053 * 00054 */ 00055 00056 #include "arch.h" 00057 ARCH_COPYRIGHT_APACHE(timeslice, c, "$URL: https://svn.apache.org/path/name/timeslice.c $ $Id: timeslice.c 0 09/28/2005 dlydick $"); 00058 00059 00060 #include <unistd.h> 00061 #include <signal.h> 00062 00063 #define _REENTRANT 00064 #include <pthread.h> 00065 #include <thread.h> /* WATCH OUT! /usr/include, not application .h */ 00066 00067 #include "jvmcfg.h" 00068 #include "classfile.h" 00069 #include "jvm.h" 00070 #include "exit.h" 00071 #include "util.h" 00072 00073 00074 /*! 00075 * @brief Thread control structure for use by 00076 * @c @b pthread_create(3), etc. 00077 */ 00078 static pthread_t posix_thread_id; 00079 00080 /*! 00081 * @brief Start the time slicing mechanism at JVM init time 00082 * 00083 * 00084 * @b Parameters: @link #rvoid rvoid@endlink 00085 * 00086 * 00087 * @returns @link #rvoid rvoid@endlink 00088 * 00089 */ 00090 rvoid timeslice_init() 00091 { 00092 /* Time slice has not expired */ 00093 pjvm->timeslice_expired = rfalse; 00094 00095 /* 00096 * Initialize the @link rthread#sleeptim rthread.sleeptime@endlink 00097 * lock w/ defult attributes 00098 */ 00099 pthread_mutex_init(&pjvm->sleeplock, (void *) rnull); 00100 00101 int rc = pthread_create(&posix_thread_id, 00102 (void *) rnull, 00103 timeslice_run, 00104 (void *) rnull); 00105 00106 if (0 != rc) 00107 { 00108 sysErrMsg("timeslice_init", "Cannot start timer"); 00109 exit_jvm(EXIT_TIMESLICE_START); 00110 /*NOTREACHED*/ 00111 } 00112 00113 /* Declare this module initialized */ 00114 jvm_timeslice_initialized = rtrue; 00115 00116 return; 00117 00118 } /* END of timeslice_init() */ 00119 00120 00121 /*! 00122 * @brief Retrieve a thread's @link rthread#sleeptime sleeptime@endlink 00123 * value @e safely during read of that variable on a given thread. 00124 * 00125 * 00126 * @param thridx Thread index of thread to read its 00127 * @link rthread#sleeptime sleeptime@endlink 00128 * value 00129 * 00130 * 00131 * @returns remaining sleep time, in timer ticks 00132 * 00133 */ 00134 jlong timeslice_get_thread_sleeptime(jvm_thread_index thridx) 00135 { 00136 jlong rc; 00137 00138 /* Lock out the @e world while retrieving any thread's sleep time */ 00139 pthread_mutex_lock(&pjvm->sleeplock); 00140 00141 rc = THREAD(thridx).sleeptime; 00142 00143 /* Unlock the @e world after sleep time retrieved */ 00144 pthread_mutex_unlock(&pjvm->sleeplock); 00145 00146 /* Report sleep time value */ 00147 return(rc); 00148 00149 } /* END of timeslice_get_thread_sleeptime() */ 00150 00151 00152 /*! 00153 * @brief Length of time slice interval as used by 00154 * @c @b setitimer(2). 00155 */ 00156 static struct itimerval timeslice_period; 00157 00158 00159 /*! 00160 * @brief Interval timer handler for the @b signal(SIGALRM) event. 00161 * 00162 * 00163 * @b Parameters: @link #rvoid rvoid@endlink 00164 * 00165 * 00166 * @returns @link #rvoid rvoid@endlink 00167 * 00168 * 00169 * @warning Eclipse users need to remember that setting a combination 00170 * of the value of @link #JVMCFG_TIMESLICE_PERIOD_ENABLE 00171 JVMCFG_TIMESLICE_PERIOD_ENABLE@endlink 00172 * to @link #rtrue rtrue@endlink, the value 00173 * of @link #JVMCFG_TIMESLICE_PERIOD_SECONDS 00174 JVMCFG_TIMESLICE_PERIOD_SECONDS@endlink to zero (0), and 00175 * the value of @link #JVMCFG_TIMESLICE_PERIOD_MICROSECONDS 00176 JVMCFG_TIMESLICE_PERIOD_MICROSECONDS@endlink to a low 00177 * milliseconds value is @e certain to interfere with the 00178 * proper operation of the GDB debug process due to the high 00179 * frequency of thread context changes per second. 00180 * The debug session @b will terminate without rhyme nor 00181 * reason. Setting the period to several seconds will 00182 * elminate this problem at the expense of time slicing 00183 * on a normal basis. For unit testing, this is not a 00184 * problem. For integration testing, you are on your own.... 00185 * 00186 */ 00187 00188 static void timeslice_tick(/* void --GCC won't allow this declaration*/) 00189 { 00190 /* Suppress SIGALRM until finished with this handler */ 00191 signal(SIGALRM, SIG_IGN); 00192 00193 /* Debug report of timer. Use ONLY for SLOW INTERVALS! */ 00194 if (JVMCFG_TIMESLICE_DEBUG_REPORT_MIN_SECONDS != 0) /* 0:= disable*/ 00195 { 00196 if (JVMCFG_TIMESLICE_DEBUG_REPORT_MIN_SECONDS <= 00197 timeslice_period.it_interval.tv_sec) 00198 { 00199 sysDbgMsg(DML9, "timeslice_tick", "tick"); 00200 } 00201 } 00202 00203 /* 00204 * Process signal by telling JVM to go to next time slice. 00205 * Also decrement sleep interval timers for sleeping, joining, 00206 * and waiting threads. 00207 */ 00208 pjvm->timeslice_expired = rtrue; 00209 threadutil_update_sleeptime_interval(); 00210 00211 /* Set next SIGALARM for next tick of the time slice timer */ 00212 signal(SIGALRM, timeslice_tick); 00213 00214 } /* END of timeslice_tick() */ 00215 00216 00217 /*! 00218 * @brief Interval timer thread. 00219 * 00220 * 00221 * @param dummy The @c @b setitimer(2) system call requires 00222 * a <b><code>(void *)</code></b> that has no 00223 * meaning here. 00224 * 00225 * 00226 * @returns The required <b><code>(void *)</code></b> is passed back, 00227 * but this function never returns until the time slice 00228 * thread is killed. 00229 * 00230 */ 00231 void *timeslice_run(void *dummy) 00232 { 00233 /* Start timer and make its first tick one period from now */ 00234 timeslice_period.it_interval.tv_sec = 00235 JVMCFG_TIMESLICE_PERIOD_SECONDS; 00236 timeslice_period.it_interval.tv_usec = 00237 JVMCFG_TIMESLICE_PERIOD_MICROSECONDS; 00238 timeslice_period.it_value.tv_sec = 00239 JVMCFG_TIMESLICE_PERIOD_SECONDS; 00240 timeslice_period.it_value.tv_usec = 00241 JVMCFG_TIMESLICE_PERIOD_MICROSECONDS; 00242 00243 /* If timer is configured to run, get it going */ 00244 if (rtrue == JVMCFG_TIMESLICE_PERIOD_ENABLE) 00245 { 00246 00247 /* 00248 * Set initial SIGALARM for timer_tick(), 00249 * arm timer to generate it. 00250 */ 00251 signal(SIGALRM, timeslice_tick); 00252 00253 int rc = setitimer(ITIMER_REAL, 00254 ×lice_period, 00255 (void *) rnull); 00256 00257 if (0 != rc) 00258 { 00259 sysErrMsg("timeslice_run", "Cannot start interval timer"); 00260 exit_jvm(EXIT_TIMESLICE_START); 00261 /*NOTREACHED*/ 00262 } 00263 } 00264 00265 /* 00266 * Do nothing except wait on timer ticks. 00267 * Eventually, the main process exits and 00268 * this thread will die along with it without 00269 * ever having left the while() loop. 00270 * 00271 * If timer is not configured to run, this loop 00272 * will never see SIGALRM and timer ticks. 00273 */ 00274 00275 while(rtrue) 00276 { 00277 yield(); 00278 } 00279 00280 /*NOTREACHED*/ 00281 return((void *) rnull); 00282 00283 } /* END of timeslice_run() */ 00284 00285 00286 /*! 00287 * @brief Shut down the time slicing mechanism for JVM shutdown. 00288 * 00289 * 00290 * @b Parameters: @link #rvoid rvoid@endlink 00291 * 00292 * 00293 * @returns @link #rvoid rvoid@endlink 00294 * 00295 */ 00296 rvoid timeslice_shutdown(rvoid) 00297 { 00298 /* Suppress SIGALRM so future tick does not happen AT ALL */ 00299 signal(SIGALRM, SIG_IGN); 00300 00301 /* Ignore error */ 00302 pthread_cancel(posix_thread_id); 00303 00304 /*! @todo Is this necessary at JVM shutdown time? */ 00305 /* pthread_mutex_destroy(&pjvm->sleeplock); */ 00306 00307 /* Declare this module uninitialized */ 00308 jvm_timeslice_initialized = rfalse; 00309 00310 return; 00311 00312 } /* END of timeslice_shutdown() */ 00313 00314 00315 /* EOF */ 00316