19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one
39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or more contributor license agreements. See the NOTICE file
49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed with this work for additional information
59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * regarding copyright ownership. The ASF licenses this file
69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to you under the Apache License, Version 2.0 (the  "License");
79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may not use this file except in compliance with the License.
89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You may obtain a copy of the License at
99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Unless required by applicable law or agreed to in writing, software
139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See the License for the specific language governing permissions and
169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * limitations under the License.
179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * $Id: CoroutineManager.java 468653 2006-10-28 07:07:05Z minchau $
209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpackage org.apache.xml.dtm.ref;
229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.BitSet;
249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.res.XMLErrorResources;
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.res.XMLMessages;
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/**
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>Support the coroutine design pattern.</p>
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>A coroutine set is a very simple cooperative non-preemptive
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * multitasking model, where the switch from one task to another is
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * performed via an explicit request. Coroutines interact according to
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the following rules:</p>
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <ul>
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <li>One coroutine in the set has control, which it retains until it
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * either exits or resumes another coroutine.</li>
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <li>A coroutine is activated when it is resumed by some other coroutine
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * for the first time.</li>
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <li>An active coroutine that gives up control by resuming another in
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the set retains its context -- including call stack and local variables
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * -- so that if/when it is resumed, it will proceed from the point at which
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * it last gave up control.</li>
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * </ul>
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>Coroutines can be thought of as falling somewhere between pipes and
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * subroutines. Like call/return, there is an explicit flow of control
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * from one coroutine to another. Like pipes, neither coroutine is
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * actually "in charge", and neither must exit in order to transfer
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * control to the other. </p>
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>One classic application of coroutines is in compilers, where both
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the parser and the lexer are maintaining complex state
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * information. The parser resumes the lexer to process incoming
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * characters into lexical tokens, and the lexer resumes the parser
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * when it has reached a point at which it has a reliably interpreted
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * set of tokens available for semantic processing. Structuring this
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * as call-and-return would require saving and restoring a
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * considerable amount of state each time. Structuring it as two tasks
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * connected by a queue may involve higher overhead (in systems which
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * can optimize the coroutine metaphor), isn't necessarily as clear in
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * intent, may have trouble handling cases where data flows in both
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * directions, and may not handle some of the more complex cases where
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * more than two coroutines are involved.</p>
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>Most coroutine systems also provide a way to pass data between the
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * source and target of a resume operation; this is sometimes referred
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to as "yielding" a value.  Others rely on the fact that, since only
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * one member of a coroutine set is running at a time and does not
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * lose control until it chooses to do so, data structures may be
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * directly shared between them with only minimal precautions.</p>
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>"Note: This should not be taken to mean that producer/consumer
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * problems should be always be done with coroutines." Queueing is
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * often a better solution when only two threads of execution are
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * involved and full two-way handshaking is not required. It's a bit
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * difficult to find short pedagogical examples that require
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * coroutines for a clear solution.</p>
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>The fact that only one of a group of coroutines is running at a
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * time, and the control transfer between them is explicit, simplifies
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * their possible interactions, and in some implementations permits
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * them to be implemented more efficiently than general multitasking.
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * In some situations, coroutines can be compiled out entirely;
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * in others, they may only require a few instructions more than a
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * simple function call.</p>
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>This version is built on top of standard Java threading, since
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * that's all we have available right now. It's been encapsulated for
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * code clarity and possible future optimization.</p>
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>(Two possible approaches: wait-notify based and queue-based. Some
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * folks think that a one-item queue is a cleaner solution because it's
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * more abstract -- but since coroutine _is_ an abstraction I'm not really
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * worried about that; folks should be able to switch this code without
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * concern.)</p>
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>%TBD% THIS SHOULD BE AN INTERFACE, to facilitate building other
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * implementations... perhaps including a true coroutine system
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * someday, rather than controlled threading. Arguably Coroutine
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * itself should be an interface much like Runnable, but I think that
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * can be built on top of this.</p>
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * */
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpublic class CoroutineManager
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** "Is this coroutine ID number already in use" lookup table.
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Currently implemented as a bitset as a compromise between
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * compactness and speed of access, but obviously other solutions
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * could be applied.
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  BitSet m_activeIDs=new BitSet();
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Limit on the coroutine ID numbers accepted. I didn't want the
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * in-use table to grow without bound. If we switch to a more efficient
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * sparse-array mechanism, it may be possible to raise or eliminate
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * this boundary.
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @xsl.usage internal
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  static final int m_unreasonableId=1024;
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Internal field used to hold the data being explicitly passed
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * from one coroutine to another during a co_resume() operation.
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * (Of course implicit data sharing may also occur; one of the reasons
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * for using coroutines is that you're guaranteed that none of the
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * other coroutines in your set are using shared structures at the time
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * you access them.)
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * %REVIEW% It's been proposed that we be able to pass types of data
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * other than Object -- more specific object types, or
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * lighter-weight primitives.  This would seem to create a potential
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * explosion of "pass x recieve y back" methods (or require
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * fracturing resume into two calls, resume-other and
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * wait-to-be-resumed), and the weight issue could be managed by
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * reusing a mutable buffer object to contain the primitive
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * (remember that only one coroutine runs at a time, so once the
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * buffer's set it won't be walked on). Typechecking objects is
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * interesting from a code-robustness point of view, but it's
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * unclear whether it makes sense to encapsulate that in the
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * coroutine code or let the callers do it, since it depends on RTTI
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * either way. Restricting the parameters to objects implementing a
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * specific CoroutineParameter interface does _not_ seem to be a net
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * win; applications can do so if they want via front-end code, but
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * there seem to be too many use cases involving passing an existing
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * object type that you may not have the freedom to alter and may
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * not want to spend time wrapping another object around.
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  Object m_yield=null;
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Expose???
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  final static int NOBODY=-1;
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  final static int ANYBODY=-1;
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Internal field used to confirm that the coroutine now waking up is
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * in fact the one we intended to resume. Some such selection mechanism
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * is needed when more that two coroutines are operating within the same
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * group.
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  int m_nextCoroutine=NOBODY;
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** <p>Each coroutine in the set managed by a single
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * CoroutineManager is identified by a small positive integer. This
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * brings up the question of how to manage those integers to avoid
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * reuse... since if two coroutines use the same ID number, resuming
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * that ID could resume either. I can see arguments for either
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * allowing applications to select their own numbers (they may want
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * to declare mnemonics via manefest constants) or generating
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * numbers on demand.  This routine's intended to support both
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * approaches.</p>
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * <p>%REVIEW% We could use an object as the identifier. Not sure
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * it's a net gain, though it would allow the thread to be its own
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * ID. Ponder.</p>
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param coroutineID  If >=0, requests that we reserve this number.
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * If <0, requests that we find, reserve, and return an available ID
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * number.
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return If >=0, the ID number to be used by this coroutine. If <0,
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * an error occurred -- the ID requested was already in use, or we
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * couldn't assign one without going over the "unreasonable value" mark
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public synchronized int co_joinCoroutineSet(int coroutineID)
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(coroutineID>=0)
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if(coroutineID>=m_unreasonableId || m_activeIDs.get(coroutineID))
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          return -1;
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    else
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // What I want is "Find first clear bit". That doesn't exist.
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // JDK1.2 added "find last set bit", but that doesn't help now.
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        coroutineID=0;
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        while(coroutineID<m_unreasonableId)
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if(m_activeIDs.get(coroutineID))
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              ++coroutineID;
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            else
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              break;
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if(coroutineID>=m_unreasonableId)
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          return -1;
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_activeIDs.set(coroutineID);
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return coroutineID;
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** In the standard coroutine architecture, coroutines are
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * identified by their method names and are launched and run up to
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * their first yield by simply resuming them; its's presumed that
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * this recognizes the not-already-running case and does the right
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * thing. We seem to need a way to achieve that same threadsafe
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * run-up...  eg, start the coroutine with a wait.
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * %TBD% whether this makes any sense...
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param thisCoroutine the identifier of this coroutine, so we can
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * recognize when we are being resumed.
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception java.lang.NoSuchMethodException if thisCoroutine isn't
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * a registered member of this group. %REVIEW% whether this is the
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * best choice.
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public synchronized Object co_entry_pause(int thisCoroutine) throws java.lang.NoSuchMethodException
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(!m_activeIDs.get(thisCoroutine))
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new java.lang.NoSuchMethodException();
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    while(m_nextCoroutine != thisCoroutine)
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        try
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            wait();
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        catch(java.lang.InterruptedException e)
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // %TBD% -- Declare? Encapsulate? Ignore? Or
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // dance widdershins about the instruction cache?
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return m_yield;
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Transfer control to another coroutine which has already been started and
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * is waiting on this CoroutineManager. We won't return from this call
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * until that routine has relinquished control.
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * %TBD% What should we do if toCoroutine isn't registered? Exception?
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param arg_object A value to be passed to the other coroutine.
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param thisCoroutine Integer identifier for this coroutine. This is the
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * ID we watch for to see if we're the ones being resumed.
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param toCoroutine  Integer identifier for the coroutine we wish to
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * invoke.
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception java.lang.NoSuchMethodException if toCoroutine isn't a
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * registered member of this group. %REVIEW% whether this is the best choice.
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public synchronized Object co_resume(Object arg_object,int thisCoroutine,int toCoroutine) throws java.lang.NoSuchMethodException
2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(!m_activeIDs.get(toCoroutine))
2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new java.lang.NoSuchMethodException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COROUTINE_NOT_AVAIL, new Object[]{Integer.toString(toCoroutine)})); //"Coroutine not available, id="+toCoroutine);
2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // We expect these values to be overwritten during the notify()/wait()
2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // periods, as other coroutines in this set get their opportunity to run.
2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_yield=arg_object;
2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_nextCoroutine=toCoroutine;
2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    notify();
2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    while(m_nextCoroutine != thisCoroutine || m_nextCoroutine==ANYBODY || m_nextCoroutine==NOBODY)
2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        try
2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // System.out.println("waiting...");
2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            wait();
2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        catch(java.lang.InterruptedException e)
2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // %TBD% -- Declare? Encapsulate? Ignore? Or
2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // dance deasil about the program counter?
2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(m_nextCoroutine==NOBODY)
2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Pass it along
2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_exit(thisCoroutine);
2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // And inform this coroutine that its partners are Going Away
2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // %REVIEW% Should this throw/return something more useful?
2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        throw new java.lang.NoSuchMethodException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COROUTINE_CO_EXIT, null)); //"CoroutineManager recieved co_exit() request");
2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return m_yield;
2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Terminate this entire set of coroutines. The others will be
2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * deregistered and have exceptions thrown at them. Note that this
3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * is intended as a panic-shutdown operation; under normal
3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * circumstances a coroutine should always end with co_exit_to() in
3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * order to politely inform at least one of its partners that it is
3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * going away.
3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * %TBD% This may need significantly more work.
3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * %TBD% Should this just be co_exit_to(,,CoroutineManager.PANIC)?
3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param thisCoroutine Integer identifier for the coroutine requesting exit.
3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public synchronized void co_exit(int thisCoroutine)
3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_activeIDs.clear(thisCoroutine);
3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_nextCoroutine=NOBODY; // %REVIEW%
3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    notify();
3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Make the ID available for reuse and terminate this coroutine,
3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * transferring control to the specified coroutine. Note that this
3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * returns immediately rather than waiting for any further coroutine
3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * traffic, so the thread can proceed with other shutdown activities.
3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param arg_object    A value to be passed to the other coroutine.
3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param thisCoroutine Integer identifier for the coroutine leaving the set.
3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param toCoroutine   Integer identifier for the coroutine we wish to
3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * invoke.
3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception java.lang.NoSuchMethodException if toCoroutine isn't a
3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * registered member of this group. %REVIEW% whether this is the best choice.
3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public synchronized void co_exit_to(Object arg_object,int thisCoroutine,int toCoroutine) throws java.lang.NoSuchMethodException
3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(!m_activeIDs.get(toCoroutine))
3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new java.lang.NoSuchMethodException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COROUTINE_NOT_AVAIL, new Object[]{Integer.toString(toCoroutine)})); //"Coroutine not available, id="+toCoroutine);
3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // We expect these values to be overwritten during the notify()/wait()
3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // periods, as other coroutines in this set get their opportunity to run.
3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_yield=arg_object;
3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_nextCoroutine=toCoroutine;
3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_activeIDs.clear(thisCoroutine);
3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    notify();
3439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
345