001/* 002 * This file is part of the Kompics component model runtime. 003 * <p> 004 * Copyright (C) 2009 Swedish Institute of Computer Science (SICS) Copyright (C) 005 * 2009 Royal Institute of Technology (KTH) 006 * <p> 007 * Kompics is free software; you can redistribute it and/or modify it under the 008 * terms of the GNU General Public License as published by the Free Software 009 * Foundation; either version 2 of the License, or (at your option) any later 010 * version. 011 * <p> 012 * This program is distributed in the hope that it will be useful, but WITHOUT 013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 014 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 015 * details. 016 * <p> 017 * You should have received a copy of the GNU General Public License along with 018 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 019 * Place - Suite 330, Boston, MA 02111-1307, USA. 020 */ 021package se.sics.kompics; 022 023import java.util.Optional; 024import java.util.LinkedList; 025import java.util.List; 026import java.util.UUID; 027import java.util.concurrent.ForkJoinTask; 028import java.util.concurrent.atomic.AtomicInteger; 029import java.util.concurrent.locks.ReentrantReadWriteLock; 030import org.slf4j.Logger; 031import se.sics.kompics.config.Config; 032import se.sics.kompics.config.ConfigUpdate; 033 034/** 035 * The <code>ComponentCore</code> class. 036 * <p> 037 * 038 * @author Cosmin Arad {@literal <[email protected]>} 039 * @author Jim Dowling {@literal <[email protected]>} 040 * @author Lars Kroll {@literal <[email protected]>} 041 */ 042@SuppressWarnings("serial") 043public abstract class ComponentCore extends ForkJoinTask<Void> implements Component { 044 045 private final UUID id = UUID.randomUUID(); 046 protected ComponentCore parent; 047 protected Config conf; 048 public static final ThreadLocal<ComponentCore> parentThreadLocal = new ThreadLocal<ComponentCore>(); 049 public static final ThreadLocal<Optional<ConfigUpdate>> childUpdate = new ThreadLocal<Optional<ConfigUpdate>>() { 050 @Override 051 protected Optional<ConfigUpdate> initialValue() { 052 return Optional.empty(); 053 } 054 }; 055 056 protected List<ComponentCore> children = new LinkedList<ComponentCore>(); 057 058 protected final ReentrantReadWriteLock childrenLock = new ReentrantReadWriteLock(); 059 protected Scheduler scheduler; 060 protected int wid; 061 062 protected abstract Logger logger(); 063 064 public ComponentCore getParent() { 065 return parent; 066 } 067 068 public Config config() { 069 return conf; 070 } 071 072 protected abstract void cleanPorts(); 073 074 public abstract Negative<ControlPort> createControlPort(); 075 076 protected void doDestroy(Component component) { 077 ComponentCore child = (ComponentCore) component; 078 child.cleanPorts(); 079 if ((child.state != State.PASSIVE) && (child.state != State.FAULTY)) { 080 logger().warn("Destroying a component before it has been stopped is not a good idea: {}", 081 child.getComponent()); 082 } 083 child.state = State.DESTROYED; 084 try { 085 childrenLock.writeLock().lock(); 086 087 children.remove(child); 088 } finally { 089 childrenLock.writeLock().unlock(); 090 } 091 } 092 093 protected void destroyTree(ComponentCore child) { 094 try { 095 childrenLock.writeLock().lock(); 096 child.childrenLock.writeLock().lock(); 097 for (ComponentCore grandchild : child.children) { 098 child.destroyTree(grandchild); 099 } 100 child.getComponent().tearDown(); 101 doDestroy(child); 102 } finally { 103 child.childrenLock.writeLock().unlock(); 104 childrenLock.writeLock().unlock(); 105 } 106 } 107 108 protected abstract void setInactive(Component child); 109 110 protected void markSubtreeAs(State s) { 111 this.state = s; 112 if (s == State.FAULTY || s == State.DESTROYED || s == State.PASSIVE) { 113 if (parent != null) { 114 parent.setInactive(this); 115 } 116 } 117 try { 118 childrenLock.readLock().lock(); 119 for (ComponentCore child : children) { 120 child.markSubtreeAs(s); 121 } 122 } finally { 123 childrenLock.readLock().unlock(); 124 } 125 } 126 127 abstract void doConfigUpdate(ConfigUpdate update); 128 129 public abstract <T extends ComponentDefinition> Component doCreate(Class<T> definition, 130 Optional<Init<T>> initEvent); 131 132 public abstract <T extends ComponentDefinition> Component doCreate(Class<T> definition, Optional<Init<T>> initEvent, 133 Optional<ConfigUpdate> update); 134 135 public abstract <P extends PortType> Negative<P> createNegativePort(Class<P> portType); 136 137 public abstract <P extends PortType> Positive<P> createPositivePort(Class<P> portType); 138 139 /* 140 * === SCHEDULING === 141 */ 142 public AtomicInteger workCount = new AtomicInteger(0); 143 protected SpinlockQueue<PortCore<?>> readyPorts = new SpinlockQueue<PortCore<?>>(); 144 145 /** 146 * Sets the scheduler. 147 * <p> 148 * 149 * @param scheduler 150 * the new scheduler 151 */ 152 public void setScheduler(Scheduler scheduler) { 153 this.scheduler = scheduler; 154 } 155 156 public void eventReceived(PortCore<?> port, KompicsEvent event, int wid) { 157 // System.err.println("Received event " + event + " on " + port.getPortType().portTypeClass + " work " + 158 // workCount.get()); 159 port.enqueue(event); 160 readyPorts.offer(port); 161 int wc = workCount.getAndIncrement(); 162 if (wc == 0) { 163 schedule(wid); 164 } 165 } 166 167 protected void schedule(int wid) { 168 if (scheduler == null) { 169 scheduler = Kompics.getScheduler(); 170 } 171 scheduler.schedule(this, wid); 172 } 173 174 public abstract void execute(int wid); 175 176 @Override 177 public void run() { 178 this.execute(0); 179 } 180 181 @Override 182 public UUID id() { 183 return this.id; 184 } 185 186 @Override 187 public boolean equals(Object obj) { 188 if (obj instanceof ComponentCore) { 189 ComponentCore cc = (ComponentCore) obj; 190 return this.id.equals(cc.id); 191 } 192 return false; 193 } 194 195 @Override 196 public int hashCode() { 197 int hash = 7; 198 hash = 59 * hash + (this.id != null ? this.id.hashCode() : 0); 199 return hash; 200 } 201 202 @Override 203 public String toString() { 204 StringBuilder sb = new StringBuilder(); 205 sb.append("Component("); 206 sb.append(id); 207 sb.append("):"); 208 sb.append(getComponent()); 209 return sb.toString(); 210 } 211 212 /* 213 * === LIFECYCLE === 214 */ 215 volatile protected Component.State state = Component.State.PASSIVE; 216 217 @Override 218 public Component.State state() { 219 return state; 220 } 221 222 /* 223 * === Relaying for package fields to Scala 224 */ 225 protected void escalateFaultToKompics(Fault fault) { 226 Kompics.handleFault(fault); 227 } 228 229 protected void markSubtreeAtAs(ComponentCore source, State s) { 230 source.markSubtreeAs(s); 231 } 232 233 protected void destroyTreeAtParentOf(ComponentCore source) { 234 source.parent.destroyTree(source); 235 } 236 237 @Override 238 public Void getRawResult() { 239 return null; 240 } 241 242 @Override 243 protected void setRawResult(Void value) { 244 return; 245 } 246 247 @Override 248 protected boolean exec() { 249 try { 250 run(); 251 return false; 252 // } catch(InterruptedException ex) { 253 // Thread.currentThread().interrupt(); 254 // return false; 255 // } 256 } catch (Throwable e) { 257 Kompics.getFaultHandler().handle(new Fault(e, this, null)); 258 throw e; 259 } 260 } 261}