Source Code Cross Referenced for Notifier.java in  » Scripting » jacl » tcl » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Notifier.java --
003:         *
004:         *	Implements the Jacl version of the Notifier class.
005:         *
006:         * Copyright (c) 1997 Sun Microsystems, Inc.
007:         *
008:         * See the file "license.terms" for information on usage and
009:         * redistribution of this file, and for a DISCLAIMER OF ALL
010:         * WARRANTIES.
011:         * 
012:         * RCS: @(#) $Id: Notifier.java,v 1.11 2006/04/27 02:16:13 mdejong Exp $
013:         *
014:         */
015:
016:        package tcl.lang;
017:
018:        import java.util.HashMap;
019:        import java.util.ArrayList;
020:
021:        // Implements the Jacl version of the Notifier class. The Notifier is
022:        // the lowest-level part of the event system. It is used by
023:        // higher-level event sources such as file, JavaBean and timer
024:        // events. The Notifier manages an event queue that holds TclEvent
025:        // objects.
026:        //
027:        // The Jacl notifier is designed to run in a multi-threaded
028:        // environment. Each notifier instance is associated with a primary
029:        // thread. Any thread can queue (or dequeue) events using the
030:        // queueEvent (or deleteEvents) call. However, only the primary thread
031:        // may process events in the queue using the doOneEvent()
032:        // call. Attepmts to call doOneEvent from a non-primary thread will
033:        // cause a TclRuntimeError.
034:        //
035:        // This class does not have a public constructor and thus cannot be
036:        // instantiated. The only way to for a Tcl extension to get an
037:        // Notifier is to call Interp.getNotifier() (or
038:        // Notifier.getNotifierForThread() ), which returns the Notifier for that
039:        // interpreter (thread).
040:
041:        public class Notifier implements  EventDeleter {
042:
043:            // First pending event, or null if none.
044:
045:            private TclEvent firstEvent;
046:
047:            // Last pending event, or null if none.
048:
049:            private TclEvent lastEvent;
050:
051:            // Last high-priority event in queue, or null if none.
052:
053:            private TclEvent markerEvent;
054:
055:            // Event that was just processed by serviceEvent
056:
057:            private TclEvent servicedEvent = null;
058:
059:            // The primary thread of this notifier. Only this thread should process
060:            // events from the event queue.
061:
062:            Thread primaryThread;
063:
064:            // Stores the Notifier for each thread.
065:
066:            private static HashMap notifierTable = new HashMap();
067:
068:            // List of registered timer handlers.
069:
070:            ArrayList timerList;
071:
072:            // Used to distinguish older timer handlers from recently-created ones.
073:
074:            int timerGeneration;
075:
076:            // True if there is a pending timer event in the event queue, false
077:            // otherwise.
078:
079:            boolean timerPending;
080:
081:            // List of registered idle handlers.
082:
083:            ArrayList idleList;
084:
085:            // Used to distinguish older idle handlers from recently-created ones.
086:
087:            int idleGeneration;
088:
089:            // Reference count of the notifier. It's used to tell when a notifier
090:            // is no longer needed.
091:
092:            int refCount;
093:
094:            /*
095:             *----------------------------------------------------------------------
096:             *
097:             * Notifier --
098:             *
099:             *	Creates a Notifier instance.
100:             *
101:             * Side effects:
102:             *	Member fields are initialized.
103:             *
104:             *----------------------------------------------------------------------
105:             */
106:
107:            private Notifier(Thread primaryThread) // The primary thread for this Notifier.
108:            {
109:                if (primaryThread == null) {
110:                    throw new NullPointerException("primaryThread");
111:                }
112:                this .primaryThread = primaryThread;
113:                firstEvent = null;
114:                lastEvent = null;
115:                markerEvent = null;
116:
117:                timerList = new ArrayList();
118:                timerGeneration = 0;
119:                idleList = new ArrayList();
120:                idleGeneration = 0;
121:                timerPending = false;
122:                refCount = 0;
123:            }
124:
125:            /*
126:             *----------------------------------------------------------------------
127:             *
128:             * getNotifierForThread --
129:             *
130:             *	Get the notifier for this thread, creating the Notifier,
131:             *	when necessary.
132:             *
133:             * Results:
134:             *	The Notifier for this thread.
135:             *
136:             * Side effects:
137:             *	The Notifier is created when necessary.
138:             *
139:             *----------------------------------------------------------------------
140:             */
141:
142:            public static synchronized Notifier getNotifierForThread(
143:                    Thread thread) // The thread that owns this Notifier.
144:            {
145:                Notifier notifier = (Notifier) notifierTable.get(thread);
146:                if (notifier == null) {
147:                    notifier = new Notifier(thread);
148:                    notifierTable.put(thread, notifier);
149:                }
150:
151:                return notifier;
152:            }
153:
154:            /*
155:             *----------------------------------------------------------------------
156:             *
157:             * preserve --
158:             *
159:             *	Increment the reference count of the notifier. The notifier will
160:             *	be kept in the notifierTable (and alive) as long as its reference
161:             *	count is greater than zero.
162:             *
163:             * Results:
164:             *	None.
165:             *
166:             * Side effects:
167:             *	The refCount is incremented.
168:             *
169:             *----------------------------------------------------------------------
170:             */
171:
172:            public synchronized void preserve() {
173:                if (refCount < 0) {
174:                    throw new TclRuntimeError(
175:                            "Attempting to preserve a freed Notifier");
176:                }
177:                ++refCount;
178:            }
179:
180:            /*
181:             *----------------------------------------------------------------------
182:             *
183:             * release --
184:             *
185:             *	Decrement the reference count of the notifier. The notifier will
186:             *	be freed when its refCount goes from one to zero.
187:             *
188:             * Results:
189:             *	None.
190:             *
191:             * Side effects:
192:             *	The notifier may be removed from the notifierTable when its
193:             *	refCount reaches zero.
194:             *
195:             *----------------------------------------------------------------------
196:             */
197:
198:            public synchronized void release() {
199:                if ((refCount == 0) && (primaryThread != null)) {
200:                    throw new TclRuntimeError(
201:                            "Attempting to release a Notifier before it's preserved");
202:                }
203:                if (refCount <= 0) {
204:                    throw new TclRuntimeError(
205:                            "Attempting to release a freed Notifier");
206:                }
207:                --refCount;
208:                if (refCount == 0) {
209:                    notifierTable.remove(primaryThread);
210:                    primaryThread = null;
211:                }
212:            }
213:
214:            /*
215:             *----------------------------------------------------------------------
216:             *
217:             * queueEvent --
218:             * 
219:             *	Insert an event into the event queue at one of three
220:             *	positions: the head, the tail, or before a floating marker.
221:             *	Events inserted before the marker will be processed in
222:             *	first-in-first-out order, but before any events inserted at
223:             *	the tail of the queue.  Events inserted at the head of the
224:             *	queue will be processed in last-in-first-out order.
225:             *
226:             * Results:
227:             *	None.
228:             *
229:             * Side effects:
230:             *	If this method is invoked by a non-primary thread, the
231:             *	primaryThread of this Notifier will be notified about the new
232:             *	event.
233:             *
234:             *----------------------------------------------------------------------
235:             */
236:
237:            public synchronized void queueEvent(TclEvent evt, // The event to put in the queue.
238:                    int position) // One of TCL.QUEUE_TAIL,
239:            // TCL.QUEUE_HEAD or TCL.QUEUE_MARK.
240:            {
241:                if (primaryThread == null) {
242:                    // queueEvent() invoked after the Notifier has been
243:                    // released. This could happen if this method was
244:                    // invoked after all the Interp objects in this
245:                    // thread have been disposed.
246:
247:                    throw new TclRuntimeError("Notifier.queueEvent() with "
248:                            + "no Interp() objects in the current thread");
249:                }
250:
251:                evt.notifier = this ;
252:
253:                if (position == TCL.QUEUE_TAIL) {
254:                    // Append the event on the end of the queue.
255:
256:                    evt.next = null;
257:
258:                    if (firstEvent == null) {
259:                        firstEvent = evt;
260:                    } else {
261:                        lastEvent.next = evt;
262:                    }
263:                    lastEvent = evt;
264:                } else if (position == TCL.QUEUE_HEAD) {
265:                    // Push the event on the head of the queue.
266:
267:                    evt.next = firstEvent;
268:                    if (firstEvent == null) {
269:                        lastEvent = evt;
270:                    }
271:                    firstEvent = evt;
272:                } else if (position == TCL.QUEUE_MARK) {
273:                    // Insert the event after the current marker event and advance
274:                    // the marker to the new event.
275:
276:                    if (markerEvent == null) {
277:                        evt.next = firstEvent;
278:                        firstEvent = evt;
279:                    } else {
280:                        evt.next = markerEvent.next;
281:                        markerEvent.next = evt;
282:                    }
283:                    markerEvent = evt;
284:                    if (evt.next == null) {
285:                        lastEvent = evt;
286:                    }
287:                } else {
288:                    // Wrong flag.
289:
290:                    throw new TclRuntimeError(
291:                            "wrong position \""
292:                                    + position
293:                                    + "\", must be TCL.QUEUE_HEAD, TCL.QUEUE_TAIL or TCL.QUEUE_MARK");
294:                }
295:
296:                if (Thread.currentThread() != primaryThread) {
297:                    notifyAll();
298:                }
299:            }
300:
301:            /*
302:             *----------------------------------------------------------------------
303:             *
304:             * deleteEvents --
305:             *
306:             *	Calls an EventDeleter for each event in the queue and deletes
307:             *	those for which deleter.deleteEvent() returns 1. Events
308:             *	for which the deleter returns 0 are left in the queue. This
309:             *	method includes code to handle the special case of the
310:             *	Notifier wanting to delete a single event after is has
311:             *	been serviced. This method is concurrent safe.
312:             *
313:             * Results:
314:             *	None.
315:             *
316:             * Side effects:
317:             *	Potentially removes one or more events from the event queue.
318:             *
319:             *----------------------------------------------------------------------
320:             */
321:
322:            public synchronized void deleteEvents(EventDeleter deleter) // The deleter that checks whether an event
323:            // should be removed.
324:            {
325:                TclEvent evt, prev;
326:                TclEvent servicedEvent = null;
327:
328:                // Handle the special case of deletion of a single event that was just
329:                // processed by the serviceEvent() method.
330:
331:                if (deleter == this ) {
332:                    servicedEvent = this .servicedEvent;
333:                    if (servicedEvent == null)
334:                        throw new TclRuntimeError(
335:                                "servicedEvent was not set by serviceEvent()");
336:                    this .servicedEvent = null;
337:                }
338:
339:                for (prev = null, evt = firstEvent; evt != null; evt = evt.next) {
340:                    if (((servicedEvent == null) && (deleter.deleteEvent(evt) == 1))
341:                            || (evt == servicedEvent)) {
342:                        if (evt == firstEvent) {
343:                            firstEvent = evt.next;
344:                        } else {
345:                            prev.next = evt.next;
346:                        }
347:                        if (evt.next == null) {
348:                            lastEvent = prev;
349:                        }
350:                        if (evt == markerEvent) {
351:                            markerEvent = prev;
352:                        }
353:                        if (evt == servicedEvent) {
354:                            servicedEvent = null;
355:                            break; // Just service this one event in the special case
356:                        }
357:                    } else {
358:                        prev = evt;
359:                    }
360:                }
361:                if (servicedEvent != null) {
362:                    throw new TclRuntimeError(
363:                            "servicedEvent was not removed from the queue");
364:                }
365:            }
366:
367:            /*
368:             *----------------------------------------------------------------------
369:             *
370:             * deleteEvent --
371:             *
372:             *	This method is required to implement the EventDeleter interface
373:             *	It is not actually used though, see deleteEvents method for
374:             *	special casing of the deletion of a specific event.
375:             *
376:             * Results:
377:             *	None.
378:             *
379:             * Side effects:
380:             *	None.
381:             *
382:             *----------------------------------------------------------------------
383:             */
384:
385:            public int deleteEvent(TclEvent evt) {
386:                throw new TclRuntimeError(
387:                        "The Notifier.deleteEvent() method should not be called");
388:            }
389:
390:            /*
391:             *----------------------------------------------------------------------
392:             *
393:             * serviceEvent --
394:             *
395:             *	Process one event from the event queue.
396:             *
397:             * Results:
398:             *	The return value is 1 if the procedure actually found an event
399:             *	to process. If no processing occurred, then 0 is returned.
400:             *
401:             * Side effects:
402:             *	Invokes all of the event handlers for the highest priority
403:             *	event in the event queue.  May collapse some events into a
404:             *	single event or discard stale events.
405:             *
406:             *----------------------------------------------------------------------
407:             */
408:
409:            int serviceEvent(int flags) // Indicates what events should be processed.
410:            // May be any combination of TCL.WINDOW_EVENTS
411:            // TCL.FILE_EVENTS, TCL.TIMER_EVENTS, or other
412:            // flags defined elsewhere.  Events not
413:            // matching this will be skipped for processing
414:            // later.
415:            {
416:                TclEvent evt;
417:
418:                // No event flags is equivalent to TCL_ALL_EVENTS.
419:
420:                if ((flags & TCL.ALL_EVENTS) == 0) {
421:                    flags |= TCL.ALL_EVENTS;
422:                }
423:
424:                // Loop through all the events in the queue until we find one
425:                // that can actually be handled.
426:
427:                evt = null;
428:                while ((evt = getAvailableEvent(evt)) != null) {
429:                    // Call the handler for the event.  If it actually handles the
430:                    // event then free the storage for the event.  There are two
431:                    // tricky things here, both stemming from the fact that the event
432:                    // code may be re-entered while servicing the event:
433:                    //
434:                    // 1. Set the "isProcessing" field to true. This is a signal to
435:                    //    ourselves that we shouldn't reexecute the handler if the
436:                    //    event loop is re-entered.
437:                    // 2. When freeing the event, must search the queue again from the
438:                    //    front to find it.  This is because the event queue could
439:                    //    change almost arbitrarily while handling the event, so we
440:                    //    can't depend on pointers found now still being valid when
441:                    //    the handler returns.
442:
443:                    evt.isProcessing = true;
444:
445:                    if (evt.processEvent(flags) != 0) {
446:                        evt.isProcessed = true;
447:                        // Don't allocate/grab the monitor for the event unless sync()
448:                        // has been called in another thread. This is thread safe
449:                        // since sync() checks the isProcessed flag before calling wait.
450:                        if (evt.needsNotify) {
451:                            synchronized (evt) {
452:                                evt.notifyAll();
453:                            }
454:                        }
455:                        // Remove this specific event from the queue
456:                        servicedEvent = evt;
457:                        deleteEvents(this );
458:                        return 1;
459:                    } else {
460:                        // The event wasn't actually handled, so we have to
461:                        // restore the isProcessing field to allow the event to be
462:                        // attempted again.
463:
464:                        evt.isProcessing = false;
465:                    }
466:
467:                    // The handler for this event asked to defer it.  Just go on to
468:                    // the next event.
469:
470:                    continue;
471:                }
472:                return 0;
473:            }
474:
475:            /*
476:             *----------------------------------------------------------------------
477:             *
478:             * getAvailableEvent --
479:             *
480:             *	Search through the internal event list to find the first event
481:             *	that is has not being processed AND the event is not equal to the given
482:             *	'skipEvent'.  This method is concurrent safe.
483:             *
484:             * Results:
485:             *	The return value is a pointer to the first found event that can be
486:             * 	processed.  If no event is found, this method returns null.
487:             *
488:             * Side effects:
489:             *	This method synchronizes on the 'notifierMutex', which will block any
490:             *	other thread from adding or removing events from the event queue.
491:             *
492:             *----------------------------------------------------------------------
493:             */
494:
495:            private synchronized TclEvent getAvailableEvent(TclEvent skipEvent) // Indicates that the given event should not
496:            // be returned.  This argument can be null.
497:            {
498:                TclEvent evt;
499:
500:                for (evt = firstEvent; evt != null; evt = evt.next) {
501:                    if ((evt.isProcessing == false)
502:                            && (evt.isProcessed == false) && (evt != skipEvent)) {
503:                        return evt;
504:                    }
505:                }
506:                return null;
507:            }
508:
509:            /*
510:             *----------------------------------------------------------------------
511:             *
512:             * doOneEvent --
513:             *
514:             *	Process a single event of some sort.  If there's no work to
515:             *	do, wait for an event to occur, then process it. May delay
516:             *	execution of process while waiting for an event, unless
517:             *	TCL.DONT_WAIT is set in the flags argument.
518:             *	
519:             * Results:
520:             *	The return value is 1 if the procedure actually found an event
521:             *	to process. If no processing occurred, then 0 is returned
522:             *	(this can happen if the TCL.DONT_WAIT flag is set or if there
523:             *	are no event handlers to wait for in the set specified by
524:             *	flags).
525:             *
526:             * Side effects:
527:             *	May delay execution of process while waiting for an event,
528:             *	unless TCL.DONT_WAIT is set in the flags argument. Event
529:             *	sources are invoked to check for and queue events. Event
530:             *	handlers may produce arbitrary side effects.
531:             *
532:             *----------------------------------------------------------------------
533:             */
534:
535:            public int doOneEvent(int flags) // Miscellaneous flag values: may be any
536:            // combination of TCL.DONT_WAIT,
537:            // TCL.WINDOW_EVENTS, TCL.FILE_EVENTS,
538:            // TCL.TIMER_EVENTS, TCL.IDLE_EVENTS,
539:            // or others defined by event sources.
540:            {
541:                final boolean debug = false;
542:
543:                int result = 0;
544:
545:                if (primaryThread == null) {
546:                    // queueEvent() invoked after the Notifier has been
547:                    // released. This could happen if this method was
548:                    // invoked after all the Interp objects in this
549:                    // thread have been disposed.
550:
551:                    throw new TclRuntimeError("Notifier.doOneEvent() with "
552:                            + "no Interp() objects in the current thread");
553:                }
554:
555:                // No event flags is equivalent to TCL_ALL_EVENTS.
556:
557:                if ((flags & TCL.ALL_EVENTS) == 0) {
558:                    flags |= TCL.ALL_EVENTS;
559:                }
560:
561:                // The core of this procedure is an infinite loop, even though
562:                // we only service one event.  The reason for this is that we
563:                // may be processing events that don't do anything inside of Tcl.
564:
565:                while (true) {
566:                    // If idle events are the only things to service, skip the
567:                    // main part of the loop and go directly to handle idle
568:                    // events (i.e. don't wait even if TCL_DONT_WAIT isn't set).
569:
570:                    if ((flags & TCL.ALL_EVENTS) == TCL.IDLE_EVENTS) {
571:                        return serviceIdle();
572:                    }
573:
574:                    long sysTime = System.currentTimeMillis();
575:
576:                    // If some timers have been expired, queue them into the
577:                    // event queue. We can't process expired times right away,
578:                    // because there may already be other events on the queue.
579:
580:                    if (!timerPending && (timerList.size() > 0)) {
581:                        TimerHandler h = (TimerHandler) timerList.get(0);
582:
583:                        if (h.atTime <= sysTime) {
584:                            TimerEvent event = new TimerEvent();
585:                            event.notifier = this ;
586:                            queueEvent(event, TCL.QUEUE_TAIL);
587:                            timerPending = true;
588:                        }
589:                    }
590:
591:                    // Service a queued event, if there are any.
592:
593:                    if (serviceEvent(flags) != 0) {
594:                        result = 1;
595:                        break;
596:                    }
597:
598:                    // There is no event on the queue. Check for idle events.
599:
600:                    if ((flags & TCL.IDLE_EVENTS) != 0) {
601:                        if (serviceIdle() != 0) {
602:                            result = 1;
603:                            break;
604:                        }
605:                    }
606:
607:                    if ((flags & TCL.DONT_WAIT) != 0) {
608:                        break;
609:                    }
610:
611:                    // We don't have any event to service. We'll wait if
612:                    // TCL.DONT_WAIT. When the following wait() call returns,
613:                    // one of the following things may happen:
614:                    //
615:                    // (1) waitTime milliseconds has elasped (if waitTime != 0);
616:                    //
617:                    // (2) The primary notifier has been notify()'ed by other threads:
618:                    //     (a) an event is queued by queueEvent().
619:                    //     (b) a timer handler was created by new TimerHandler();
620:                    //     (c) an idle handler was created by new IdleHandler();
621:                    // (3) We receive an InterruptedException.
622:                    //
623:
624:                    try {
625:                        // Don't acquire the monitor until we are about to wait
626:                        // for notification from another thread. It is critical
627:                        // that this entire method not be synchronized since
628:                        // a call to processEvent via serviceEvent could take
629:                        // a very long time. We don't want the monitor held
630:                        // during that time since that would force calls to
631:                        // queueEvent in other threads to wait.
632:
633:                        synchronized (this ) {
634:                            if (timerList.size() > 0) {
635:                                TimerHandler h = (TimerHandler) timerList
636:                                        .get(0);
637:                                long waitTime = h.atTime - sysTime;
638:                                if (waitTime > 0) {
639:                                    wait(waitTime);
640:                                }
641:                            } else {
642:                                wait();
643:                            }
644:                        } // synchronized (this)
645:                    } catch (InterruptedException e) {
646:                        // We ignore any InterruptedException and loop continuously
647:                        // until we receive an event.
648:                    }
649:                }
650:
651:                return result;
652:            }
653:
654:            /*
655:             *----------------------------------------------------------------------
656:             *
657:             * serviceIdle --
658:             *
659:             *	Service all idle handlers that have been registered in the
660:             *	notifier.
661:             *
662:             * Results:
663:             *	1 if any idle handlers have been processed. 0 otherwise.
664:             *
665:             * Side effects:
666:             *	The idle handlers may have arbitrary side effects.
667:             *
668:             *----------------------------------------------------------------------
669:             */
670:
671:            private int serviceIdle() {
672:                int result = 0;
673:                int gen = idleGeneration;
674:                idleGeneration++;
675:
676:                // The code below is trickier than it may look, for the following
677:                // reasons:
678:                //
679:                // 1. New handlers can get added to the list while the current
680:                //    one is being processed.  If new ones get added, we don't
681:                //    want to process them during this pass through the list (want
682:                //    to check for other work to do first).  This is implemented
683:                //    using the generation number in the handler:  new handlers
684:                //    will have a different generation than any of the ones currently
685:                //    on the list.
686:                // 2. The handler can call doOneEvent, so we have to remove
687:                //    the handler from the list before calling it. Otherwise an
688:                //    infinite loop could result.
689:
690:                while (idleList.size() > 0) {
691:                    IdleHandler h = (IdleHandler) idleList.get(0);
692:                    if (h.generation > gen) {
693:                        break;
694:                    }
695:                    idleList.remove(0);
696:                    if (h.invoke() != 0) {
697:                        result = 1;
698:                    }
699:                }
700:
701:                return result;
702:            }
703:
704:            /*
705:             *----------------------------------------------------------------------
706:             *
707:             * hasActiveInterps --
708:             *
709:             *	Return true if this Notifier is processing events for 1
710:             *	or more active Interp objects. When an Interp is disposed()
711:             *	of it decrements the refCount of the Notifier object.
712:             *	When the last active Interp in a thread is disposed of,
713:             *	the Notifier is disposed of. This method will return true
714:             *	for a Notifier object that has active Interp object and
715:             *	false when the Notifier has been disposed of because the
716:             *	last active interp was disposed of.
717:             *
718:             * Results:
719:             *	None.
720:             *
721:             * Side effects:
722:             *	None.
723:             *
724:             *----------------------------------------------------------------------
725:             */
726:
727:            public synchronized boolean hasActiveInterps() {
728:                if (primaryThread == null) {
729:                    return false;
730:                } else {
731:                    return true;
732:                }
733:            }
734:
735:            /*
736:             *----------------------------------------------------------------------
737:             *
738:             * processTclEvents --
739:             *
740:             *	This util method is provided for use in a thread
741:             *	dedicated to processing events from the Tcl event queue.
742:             *	This method must only be used as the outermost event
743:             *	processing loop. It is not legal to use this method
744:             *	from any code that could be invoked by Tcl. This
745:             *	method supports interps that will make use of the
746:             *	setInterrupted() API.
747:             *	
748:             *	If only one Interp exists in the thread and the
749:             *	interp is interrupted, then this method will return.
750:             *	If more than one interp exists in the thread and
751:             *	one interp is interrupted, then events for the other
752:             *	interps will continue to be processed. This method
753:             *	will return when all the interps in the current
754:             *	thread have been disposed of. This is a convience
755:             *	method only, there is no reason this logic could
756:             *	not appear in user code.
757:             *
758:             *----------------------------------------------------------------------
759:             */
760:
761:            public static void processTclEvents(Notifier notifier) {
762:                while (notifier.hasActiveInterps()) {
763:                    try {
764:                        notifier.doOneEvent(TCL.ALL_EVENTS);
765:                    } catch (TclInterruptedException tie) {
766:                        tie.disposeInterruptedInterp();
767:                    }
768:                }
769:
770:                // The while loop will exit when the last
771:                // interp is disposed of. If this was
772:                // called by Thread.run() then the thread
773:                // will die when that method terminates.
774:                // If "exit" is called the process will
775:                // terminate without unwinding the stack.
776:
777:                return;
778:            }
779:
780:        } // end Notifier
781:
782:        // This class is used to service timer events. When one or more timers
783:        // have expired but not processed, one TimerEvent will be generated
784:        // and put into the event queue. When the TimerEvent is pulled off the
785:        // queue, it will process all expired timers in a bunch.
786:
787:        class TimerEvent extends TclEvent {
788:
789:            // The notifier that owns this TimerEvent.
790:
791:            Notifier notifier;
792:
793:            /*
794:             *----------------------------------------------------------------------
795:             *
796:             * TimerHandlerEventProc -> processEvent
797:             *
798:             *	This function is called by Tcl_ServiceEvent when a timer event reaches
799:             *	the front of the event queue. This function handles the event by
800:             *	invoking the callbacks for all timers that are ready.
801:             *
802:             * Results:
803:             *	Returns 1 if the event was handled, meaning it should be removed from
804:             *	the queue. Returns 0 if the event was not handled, meaning it should
805:             *	stay on the queue. The only time the event isn't handled is if the
806:             *	TCL.TIMER_EVENTS flag bit isn't set.
807:             *
808:             * Side effects:
809:             *	The TimerHandler may have arbitrary side effects while
810:             *	processing the event.
811:             *
812:             *----------------------------------------------------------------------
813:             */
814:
815:            public int processEvent(int flags) // Same as flags passed to Notifier.doOneEvent.
816:            {
817:                // Do nothing if timers aren't enabled. This leaves the event on the
818:                // queue, so we will get to it as soon as ServiceEvents() is called with
819:                // timers enabled.
820:
821:                if ((flags & TCL.TIMER_EVENTS) == 0) {
822:                    return 0;
823:                }
824:
825:                long sysTime = System.currentTimeMillis();
826:                int gen = notifier.timerGeneration;
827:                notifier.timerGeneration++;
828:
829:                // The code below is trickier than it may look, for the following
830:                // reasons:
831:                //
832:                // 1. New handlers can get added to the list while the current
833:                //    one is being processed.  If new ones get added, we don't
834:                //    want to process them during this pass through the list to
835:                //    avoid starving other event sources. This is implemented
836:                //    using the timer generation number: new handlers will have
837:                //    a newer generation number than any of the ones currently on
838:                //    the list.
839:                // 2. The handler can call doOneEvent, so we have to remove
840:                //    the handler from the list before calling it. Otherwise an
841:                //    infinite loop could result.
842:                // 3. Tcl_DeleteTimerHandler can be called to remove an element from the
843:                //	  list while a handler is executing, so the list could change
844:                //	  structure during the call.
845:                // 4. Because we only fetch the current time before entering the loop,
846:                //    the only way a new timer will even be considered runnable is if
847:                //	  its expiration time is within the same millisecond as the
848:                //	  current time.  This is fairly likely on Windows, since it has
849:                //	  a course granularity clock. Since timers are placed
850:                //	  on the queue in time order with the most recently created
851:                //    handler appearing after earlier ones with the same expiration
852:                //	  time, we don't have to worry about newer generation timers
853:                //	  appearing before later ones.
854:
855:                notifier.timerPending = false;
856:
857:                while (notifier.timerList.size() > 0) {
858:                    TimerHandler h = (TimerHandler) notifier.timerList.get(0);
859:                    if (h.generation > gen) {
860:                        break;
861:                    }
862:                    if (h.atTime > sysTime) {
863:                        break;
864:                    }
865:                    notifier.timerList.remove(0);
866:                    h.invoke();
867:                }
868:
869:                return 1;
870:            }
871:
872:        } // end TimerEvent
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.