View Javadoc

1   // jq_InterrupterThread.java, created Mon Apr  9  1:52:50 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Scheduler;
5   
6   import joeq.Allocator.CodeAllocator;
7   import joeq.Class.PrimordialClassLoader;
8   import joeq.Class.jq_Class;
9   import joeq.Class.jq_InstanceMethod;
10  import joeq.Memory.CodeAddress;
11  import joeq.Memory.HeapAddress;
12  import joeq.Memory.StackAddress;
13  import joeq.Runtime.Debug;
14  import joeq.Runtime.SystemInterface;
15  import joeq.Runtime.Unsafe;
16  import jwutil.util.Assert;
17  
18  /*
19   * @author  John Whaley <jwhaley@alum.mit.edu>
20   * @version $Id: jq_InterrupterThread.java 1941 2004-09-30 03:37:06Z joewhaley $
21   */
22  public class jq_InterrupterThread extends Thread {
23  
24      public static /*final*/ boolean TRACE = false;
25      public static final boolean STATISTICS = true;
26  
27      jq_InterrupterThread(jq_NativeThread other_nt) {
28          this.other_nt = other_nt;
29          if (TRACE)
30              SystemInterface.debugwriteln(
31                  "Initialized timer interrupt for native thread " + other_nt);
32          myself = ThreadUtils.getJQThread(this);
33          myself.disableThreadSwitch();
34          this.tid =
35              SystemInterface.create_thread(
36                  _run.getDefaultCompiledVersion().getEntrypoint(),
37                  HeapAddress.addressOf(this));
38          jq_NativeThread my_nt = new jq_NativeThread(myself);
39          my_nt.getCodeAllocator().init();
40          my_nt.getHeapAllocator().init();
41          // start it up
42          SystemInterface.resume_thread(this.tid);
43      }
44  
45      // C thread handles
46      private int tid, pid;
47      private jq_NativeThread other_nt;
48      private jq_Thread myself;
49      // for convenience, so we don't have to call Reflection.getfield_A
50  
51      private int enabledCount;
52      private int disabledCount;
53      
54      public void dumpStatistics() {
55          Debug.write("enabled=");
56          Debug.write(enabledCount);
57          Debug.write(" disabled=");
58          Debug.writeln(disabledCount);
59      }
60      
61      public static int QUANTA = 10;
62  
63      public void run() {
64          this.pid = SystemInterface.init_thread();
65          Unsafe.setThreadBlock(this.myself); //  change pointer to thread currently executing
66          // set to a high priority so we don't starve.
67          SystemInterface.set_thread_priority(this.tid, SystemInterface.THREAD_PRIORITY_TIME_CRITICAL);
68          for (;;) {
69              SystemInterface.msleep(QUANTA);
70              other_nt.suspend();
71              // The other thread may hold a system lock, so outputting any debug info here may lead to deadlock
72              jq_Thread javaThread = other_nt.getCurrentJavaThread();
73              if (javaThread.isThreadSwitchEnabled()) {
74                  if (STATISTICS) ++enabledCount;
75                  if (TRACE)
76                      SystemInterface.debugwriteln(
77                          "TICK! " + other_nt + " Java Thread = " + javaThread);
78                  javaThread.disableThreadSwitch();
79                  Assert._assert(other_nt.getCurrentJavaThread() == javaThread);
80                  jq_RegisterState regs = javaThread.getRegisterState();
81                  regs.setContextFlags(
82                      jq_RegisterState.CONTEXT_CONTROL
83                          | jq_RegisterState.CONTEXT_INTEGER
84                          | jq_RegisterState.CONTEXT_FLOATING_POINT);
85                  boolean b = other_nt.getContext(regs);
86                  if (!b) {
87                      if (TRACE)
88                          SystemInterface.debugwriteln(
89                              "Failed to get thread context for " + other_nt);
90                  } else {
91                      if (TRACE)
92                          SystemInterface.debugwriteln(
93                              other_nt
94                                  + " : "
95                                  + javaThread
96                                  + " ip="
97                                  + regs.getEip().stringRep()
98                                  + " sp="
99                                  + regs.getEsp().stringRep()
100                                 + " cc="
101                                 + CodeAllocator.getCodeContaining(regs.getEip()));
102                     // simulate a call to threadSwitch method
103                     regs.setEsp(
104                         (StackAddress) regs.getEsp().offset(
105                             -HeapAddress.size()));
106                     regs.getEsp().poke(HeapAddress.addressOf(other_nt));
107                     regs.setEsp(
108                         (StackAddress) regs.getEsp().offset(
109                             -CodeAddress.size()));
110                     regs.getEsp().poke(regs.getEip());
111                     regs.setEip(
112                         jq_NativeThread
113                             ._threadSwitch
114                             .getDefaultCompiledVersion()
115                             .getEntrypoint());
116                     regs.setContextFlags(jq_RegisterState.CONTEXT_CONTROL);
117                     b = other_nt.setContext(regs);
118                     if (!b) {
119                         if (TRACE)
120                             SystemInterface.debugwriteln(
121                                 "Failed to set thread context for " + other_nt);
122                     } else {
123                         if (TRACE)
124                             SystemInterface.debugwriteln(
125                                 other_nt
126                                     + " : simulating a call to threadSwitch");
127                     }
128                 }
129             } else {
130                 // the current Java thread does not have thread switching enabled.
131                 if (STATISTICS) ++disabledCount;
132                 //if (TRACE) SystemInterface.debugwriteln(other_nt+" : "+javaThread+" Thread switch not enabled");
133             }
134             other_nt.resume();
135         }
136     }
137 
138     public static final jq_Class _class;
139     public static final jq_InstanceMethod _run;
140     static {
141         _class =
142             (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType(
143                 "Ljoeq/Scheduler/jq_InterrupterThread;");
144         _run = _class.getOrCreateInstanceMethod("run", "()V");
145     }
146 }