1 29 30 package com.caucho.util; 31 32 import com.caucho.log.Log; 33 34 import java.lang.reflect.Method ; 35 import java.util.logging.Level ; 36 import java.util.logging.Logger ; 37 38 44 public class Alarm implements ThreadTask { 45 static private final Logger log = Log.open(Alarm.class); 46 static private final Integer timeLock = new Integer (0); 47 48 static private volatile long _currentTime = System.currentTimeMillis(); 49 50 static private int _concurrentAlarmThrottle = 5; 51 52 static private Object _queueLock = new Object (); 53 54 static private AlarmThread _alarmThread; 55 56 static private Alarm []_heap = new Alarm[256]; 57 static private int _heapTop; 58 59 static private volatile int _runningAlarmCount; 60 61 static private long _testTime; 62 static private int _testCount; 63 64 static private final Method _nanoTimeMethod; 65 66 private long _wakeTime; 67 private AlarmListener _listener; 68 private ClassLoader _contextLoader; 69 private String _name; 70 71 private int _heapIndex = 0; 72 73 private volatile boolean _isRunning; 74 75 static { 76 _currentTime = System.currentTimeMillis(); 77 _alarmThread = new AlarmThread(); 78 _alarmThread.start(); 79 80 Method nanoTimeMethod; 81 82 try 83 { 84 nanoTimeMethod = System .class.getMethod("nanoTime", null); 85 } 86 catch (NoSuchMethodException e) 87 { 88 nanoTimeMethod = null; 89 } 90 91 _nanoTimeMethod = nanoTimeMethod; 92 } 93 94 98 protected Alarm() 99 { 100 _name = "alarm"; 101 } 102 103 107 public Alarm(AlarmListener listener) 108 { 109 this("alarm[" + listener + "]", listener); 110 } 111 112 116 public Alarm(String name, AlarmListener listener) 117 { 118 this(name, listener, Thread.currentThread().getContextClassLoader()); 119 } 120 121 125 public Alarm(String name, AlarmListener listener, ClassLoader loader) 126 { 127 _name = name; 128 129 setListener(listener); 130 setContextLoader(loader); 131 } 132 133 140 public Alarm(String name, AlarmListener listener, long delta) 141 { 142 this(listener); 143 144 _name = name; 145 queue(delta); 146 } 147 153 public Alarm(AlarmListener listener, long delta) 154 { 155 this(listener); 156 157 queue(delta); 158 } 159 160 163 public String getName() 164 { 165 return _name; 166 } 167 168 171 protected void setName(String name) 172 { 173 _name = name; 174 } 175 176 180 public static long getCurrentTime() 181 { 182 return _currentTime; 183 } 184 185 188 public static long getExactTime() 189 { 190 if (_testTime > 0) 191 return _testTime; 192 else 193 return System.currentTimeMillis(); 194 } 195 196 199 public static long getExactTimeNanoseconds() 200 { 201 if (_testTime > 0) 202 return _testTime * 1000000L; 203 204 return getExactTime() * 1000000L; 205 } 206 207 210 public static boolean isTest() 211 { 212 return _testTime > 0; 213 } 214 215 218 public long getWakeTime() 219 { 220 return _wakeTime; 221 } 222 223 226 public AlarmListener getListener() 227 { 228 return _listener; 229 } 230 231 234 public void setListener(AlarmListener listener) 235 { 236 _listener = listener; 237 } 238 239 242 public void setContextLoader(ClassLoader loader) 243 { 244 _contextLoader = loader; 245 } 246 247 250 public ClassLoader getContextLoader() 251 { 252 return _contextLoader; 253 } 254 255 258 public boolean isQueued() 259 { 260 return _heapIndex != 0; 261 } 262 263 266 boolean isRunning() 267 { 268 return _isRunning; 269 } 270 271 276 public void queue(long delta) 277 { 278 synchronized (_queueLock) { 279 if (_heapIndex > 0) 280 dequeueImpl(this); 281 282 long wakeTime = delta + getCurrentTime(); 283 _wakeTime = wakeTime; 284 285 insertImpl(this); 286 } 287 } 288 289 292 public void dequeue() 293 { 294 synchronized (_queueLock) { 295 if (_heapIndex > 0) 296 dequeueImpl(this); 297 } 298 } 299 300 303 public void run() 304 { 305 try { 306 handleAlarm(); 307 } catch (Throwable e) { 308 log.log(Level.WARNING, e.toString(), e); 309 } finally { 310 synchronized (_queueLock) { 311 _isRunning = false; 312 _runningAlarmCount--; 313 } 314 } 315 } 316 317 320 private void handleAlarm() 321 { 322 AlarmListener listener = getListener(); 323 324 if (listener == null) 325 return; 326 327 Thread thread = Thread.currentThread(); 328 ClassLoader loader = getContextLoader(); 329 330 if (loader != null) 331 thread.setContextClassLoader(loader); 332 else 333 thread.setContextClassLoader(ClassLoader.getSystemClassLoader()); 334 335 try { 336 listener.handleAlarm(this); 337 } finally { 338 thread.setContextClassLoader(ClassLoader.getSystemClassLoader()); 339 } 340 } 341 342 345 public void close() 346 { 347 dequeue(); 348 _listener = null; 349 _contextLoader = null; 350 } 351 352 355 static Alarm extractAlarm() 356 { 357 long now = getCurrentTime(); 358 359 synchronized (_queueLock) { 360 Alarm []heap = _heap; 361 362 Alarm alarm = heap[1]; 363 364 if (alarm == null) 365 return null; 366 else if (now < alarm._wakeTime) 367 return null; 368 369 dequeueImpl(alarm); 370 371 return alarm; 372 } 373 } 374 375 378 private static void insertImpl(Alarm item) 379 { 380 if (item._heapIndex != 0) 381 throw new IllegalStateException (); 382 383 if (_heap.length <= _heapTop + 2) { 385 Alarm []newHeap = new Alarm[2 * _heap.length]; 386 System.arraycopy(_heap, 0, newHeap, 0, _heap.length); 387 _heap = newHeap; 388 } 389 390 Alarm []heap = _heap; 391 392 int i = ++_heapTop; 393 int parent; 394 Alarm alarm; 395 long wakeTime = item._wakeTime; 396 397 while (i > 1 && wakeTime < (alarm = heap[parent = (i >> 1)])._wakeTime) { 398 heap[i] = alarm; 399 alarm._heapIndex = i; 400 i = parent; 401 } 402 403 heap[i] = item; 404 item._heapIndex = i; 405 406 if (_heapTop < i) 407 throw new IllegalStateException (); 408 } 409 410 413 private static void dequeueImpl(Alarm item) 414 { 415 int i = item._heapIndex; 416 417 if (i < 1) 418 return; 419 420 if (_heapTop < i) 421 throw new IllegalStateException ("bad heap: " + _heapTop + " index:" + i); 422 423 Alarm []heap = _heap; 424 425 if (_heapTop < 1) 426 throw new IllegalStateException (); 427 428 int size = _heapTop--; 429 430 heap[i] = heap[size]; 431 heap[i]._heapIndex = i; 432 heap[size] = null; 433 434 item._heapIndex = 0; 435 436 if (size == i) 437 return; 438 439 if (item._wakeTime < heap[i]._wakeTime) { 440 while (i < size) { 441 item = heap[i]; 442 443 int minIndex = i; 444 long minWakeTime = item._wakeTime; 445 446 int left = i << 1; 447 if (left < size && heap[left]._wakeTime < minWakeTime) { 448 minIndex = left; 449 minWakeTime = heap[left]._wakeTime; 450 } 451 452 int right = left + 1; 453 if (right < size && heap[right]._wakeTime < minWakeTime) 454 minIndex = right; 455 456 if (i == minIndex) 457 return; 458 459 heap[i] = heap[minIndex]; 460 heap[i]._heapIndex = i; 461 heap[minIndex] = item; 462 item._heapIndex = minIndex; 463 464 i = minIndex; 465 } 466 } 467 else { 468 int parent; 469 Alarm alarm; 470 item = heap[i]; 471 long wakeTime = item._wakeTime; 472 473 while (i > 1 && wakeTime < (alarm = heap[parent = (i >> 1)])._wakeTime) { 474 heap[i] = alarm; 475 alarm._heapIndex = i; 476 i = parent; 477 } 478 479 heap[i] = item; 480 item._heapIndex = i; 481 } 482 } 483 484 486 static void testClear() 487 { 488 for (; _heapTop > 0; _heapTop--) { 489 Alarm alarm = _heap[_heapTop]; 490 alarm._heapIndex = 0; 491 _heap[_heapTop] = null; 492 } 493 } 494 495 static void setTestTime(long time) 496 { 497 _testTime = time; 498 499 if (_testTime > 0) { 500 if (time < _currentTime) { 501 testClear(); 502 } 503 504 _currentTime = time; 505 } 506 else 507 _currentTime = System.currentTimeMillis(); 508 509 Alarm alarm; 510 511 Thread thread = Thread.currentThread(); 512 ClassLoader oldLoader = thread.getContextClassLoader(); 513 514 try { 515 while ((alarm = Alarm.extractAlarm()) != null) { 516 alarm.run(); 517 } 518 } finally { 519 thread.setContextClassLoader(oldLoader); 520 } 521 522 try { 523 Thread.currentThread().sleep(10); 524 } catch (Exception e) { 525 } 526 } 527 528 public String toString() 529 { 530 return "Alarm[" + _name + "]"; 531 } 532 533 static class AlarmThread extends Thread { 534 private CoordinatorTask _coordinator = new CoordinatorTask(); 535 536 public void run() 537 { 538 while (true) { 539 try { 540 if (_testTime > 0) 541 _currentTime = _testTime; 542 else 543 _currentTime = System.currentTimeMillis(); 544 545 _coordinator.schedule(); 546 547 Thread.sleep(500); 548 } catch (Throwable e) { 549 } 550 } 551 } 552 553 AlarmThread() 554 { 555 super("resin-alarm"); 556 setDaemon(true); 557 } 558 } 559 560 private static class CoordinatorTask implements ThreadTask { 561 private boolean _isRunning; 562 563 566 void schedule() 567 { 568 boolean isRunning; 569 570 synchronized (this) { 571 isRunning = _isRunning; 572 _isRunning = true; 573 } 574 575 if (! isRunning) 576 ThreadPool.getThreadPool().schedulePriority(this); 577 } 578 579 582 public void run() 583 { 584 try { 585 Thread thread = Thread.currentThread(); 586 588 590 Alarm alarm; 591 592 while ((alarm = Alarm.extractAlarm()) != null) { 593 if (_concurrentAlarmThrottle < _runningAlarmCount) { 596 try { 597 Thread.sleep(5); 598 } catch (Throwable e) { 599 } 600 } 601 602 ThreadPool.getThreadPool().startPriority(alarm); 603 } 604 605 } finally { 607 _isRunning = false; 608 } 609 } 610 } 611 } 612 | Popular Tags |