📄 channel.java
字号:
// local.dialogic.Channel abstract class
// $Id: Channel.java,v 1.9 2003/11/13 11:45:04 cgm8 Exp $
/*
* Copyright (c) 1999 Carlos G Mendioroz.
*
* This file is part of D4J.
*
* D4J is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* D4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Report problems and direct all questions to:
*
* tron@acm.org
*/
package local.dialogic;
import java.util.*;
public abstract class Channel extends Observable {
// Class variables
static private java.util.Vector channelAtDev; // Class instances
static private java.util.Vector resourceAtDev; // registered resources
static private PollThread pollThread;
static private Object eventLock = new Object(); // thing to lock on.
static private LinkedList holdEvents = new LinkedList();; // in the mean time...
static private boolean hold = false; // executing atomic
static protected boolean GC = false; // use Global Call event fn
static {
channelAtDev = new java.util.Vector(5,4);
resourceAtDev = new java.util.Vector(5,4);
pollThread = new PollThread();
pollThread.setDaemon(true);
pollThread.setName("Dialogic polling thread");
pollThread.start();
}
/**
* Used to carry out an action which will _never_ have an event fire during it.
* stops the event queue - so r should be quick and deterministic.
* In future it could be run on the event thread - a'la invokeLater() in swing
*/
public static void atomicAction(Runnable r){
synchronized(eventLock) {
hold = true;
}
r.run();
synchronized(eventLock) {
EVT evt;
hold = false;
while(holdEvents.size() > 0) {
evt = (EVT)holdEvents.removeFirst();
handleEvent(evt);
}
}
}
/*
* waitevtex is no good because there is no efficient
* way of knowing of new devices I care about.
* We need a dynamic way of asking for events, i.e. PollThread at Channel
*
* This is done via signal handling in Linux. To have the same class,
* we just throw an exception if we call waitevt() in Linux, and let
* the poller silently die...
*/
private static class PollThread extends Thread {
// Run: poll events and hold last
public void run()
{
EVT evt;
if ((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0) {
System.out.println("Channel Poll thread started");
}
try {
while (true) {
evt = new EVT();
Dialogic.sr_waitevt(evt);
if (evt.dev == 0) {
if ((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0) {
System.out.println("Channel Poll thread stopped");
}
return;
}
handleEvent(evt);
}
} catch (RuntimeException re) {
if ((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0) {
System.out.println("Channel Poll thread stopped");
}
}
}
}
protected static void handleEvent(EVT evt) {
// Guard from dispatching events generated by
// atomicAction until completion
Channel ch = null;
ResourceServer res = null;
// Support for atomicAction: action not interrupted by events.
// It's only important, AFAIK, at open time when we want events to be dispatched
// only after device had an oportunity to register.
// Old implementation used to just hold, but this is a bad idea in the linux
// implementation that is monothreaded as far as events go, and blocks all driver
// comunication, i.e., big possibility for deadlock.
if (hold) {
synchronized(eventLock){
// still holding...
if(hold) {
holdEvents.add(evt);
return;
}
}
}
if (GC)
GCChannel.gc_getMeta(evt); // No Dialogic indirection here...
try {
res = (ResourceServer)resourceAtDev.elementAt(evt.dev);
} catch (ArrayIndexOutOfBoundsException x ) {
if((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0){
System.err.println("Got event before handler registered: "+evt);
}
}
if (res != null) {
if ((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0)
System.out.println(new java.util.Date().toString().substring(11,20) +
res + ": " + evt);
res.service(evt);
} else {
dispatch(evt);
}
}
public static void dispatch(EVT evt) {
Channel ch = null;
try {
ch = (Channel)channelAtDev.elementAt(evt.dev);
} catch (ArrayIndexOutOfBoundsException x ) {
if((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0){
System.err.println("Got event before handler registered: "+evt);
}
}
if (ch != null) {
if ((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0)
System.out.println(new java.util.Date().toString().substring(11,20) +
Device.atDev(evt.dev) + ": " + evt);
ch.newEvent(evt);
} else {
if ((Dialogic.debug & Dialogic.DEBUG_EVSRC) != 0){
System.out.println("unclaimed event: " + evt
+"("+ evt.dev + "/" + evt.line + ")");
}
}
}
// Utility fn to interrupt (and join) all channel group threads
// waiting for ThreadGroup.interrupt()/join() to be implemented.
// We leave serviceThread alone...and myself!
/* 5/3/02 it seems that sometimes we kill the thread that is clearing
* the channel and then let the channel in an unusable state :-( */
public static void stopGroup(Channel ch) {
if ((Dialogic.debug & Dialogic.DEBUG_CHANNEL) != 0 && ch.group != null)
System.out.println("StopGroup("+ ch.toString()+ ")");
if (ch.group == null)
return;
int n = ch.group.activeCount();
if (n == 0)
return;
Thread list[] = new Thread[n];
int count = ch.group.enumerate(list);
Thread me = Thread.currentThread();
// Interrupt all of them, then join !
for (int i = 0; i < count; i++) {
if (list[i] != ch.serviceThread && list[i] != me)
list[i].interrupt();
}
for (int i = 0; i < count; i++) {
if (list[i] != ch.serviceThread && list[i] != me) {
try {
list[i].join();
}
catch(InterruptedException ie) {
if ((Dialogic.debug & Dialogic.DEBUG_CHANNEL) != 0 && ch.group != null)
System.out.println("StopGroup("+ ch.toString()+ ") interrupted");
Thread.currentThread().interrupt();
}
}
}
if (me != ch.serviceThread)
ch.serviceThread.interrupt(); // He has to know!
if ((Dialogic.debug & Dialogic.DEBUG_CHANNEL) != 0 && ch.group != null)
System.out.println("StopGroup("+ ch.toString()+ ") exit");
}
/**
* setGroup: recreate the service thread association
* making a new group for this channel...
*/
public void setGroup() {
serviceThread = Thread.currentThread();
group = serviceThread.getThreadGroup();
}
// Variables
CallHandler handler = null;
// resource used to be a Resource but now we support a set of them...
java.util.Vector resource;
// events is logically a queue. It used to be a com.objectspace.Queue
// but now we use JDK2's LinkedList in favour of easier deployment.
private LinkedList events;
private boolean serviceActive = false;
protected EVT lastEvent = null;
protected Call call = null;
/**
* Visible state of channel (via getState() and observer interface).
* The actual Channel implementation is responsible
* for updating it using setState({OOS|FREE|INCOMING|OUTGOING}).
*/
protected Integer state = OOS;
ThreadGroup group = null;
Thread serviceThread = null;
//
public Channel() {
events = new LinkedList();
resource = new java.util.Vector(2,1);
}
protected void register(Device dev) {
if (channelAtDev.size() <= dev.device) {
channelAtDev.setSize(dev.device + 1);
resourceAtDev.setSize(dev.device + 1);
}
channelAtDev.setElementAt(this, dev.device);
dev.channel = this;
if ((Dialogic.debug & Dialogic.DEBUG_EVDST) != 0)
System.out.println("Registered: " + dev);
}
protected void unregister(Device dev) {
channelAtDev.setElementAt(null, dev.device);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -