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