Skip to content

Commit

Permalink
Merge pull request #51 from ropalka/1.2-fixes
Browse files Browse the repository at this point in the history
Another round of MSC fixes
  • Loading branch information
dmlloyd committed Oct 30, 2017
2 parents 7532a1f + d07879a commit 38bbe12
Show file tree
Hide file tree
Showing 73 changed files with 1,141 additions and 11,525 deletions.
79 changes: 0 additions & 79 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@

<properties>
<version.apiviz>1.3.2.GA</version.apiviz>
<version.byteman>3.0.0</version.byteman>
<version.jboss-logmanager>1.4.1.Final</version.jboss-logmanager>
<version.jboss-logging>3.1.3.GA</version.jboss-logging>
<version.jboss-logging-processor>1.1.0.Final</version.jboss-logging-processor>
Expand Down Expand Up @@ -78,24 +77,6 @@
<version>${version.junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.byteman</groupId>
<artifactId>byteman</artifactId>
<version>${version.byteman}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.byteman</groupId>
<artifactId>byteman-bmunit</artifactId>
<version>${version.byteman}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.byteman</groupId>
<artifactId>byteman-install</artifactId>
<version>${version.byteman}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand All @@ -112,14 +93,9 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- uncomment this to enable byteman rule debug messages
<argLine>-Dorg.jboss.byteman.debug</argLine> -->
<includes>
<include>**/*TestCase.java</include>
</includes>
<excludes>
<exclude>org/jboss/msc/bench/*.java</exclude>
</excludes>
<systemProperties>
<property>
<name>test.log.output</name>
Expand All @@ -129,63 +105,8 @@
<name>java.util.logging.manager</name>
<value>org.jboss.logmanager.LogManager</value>
</property>
<property>
<name>racecondition.dir</name>
<value>${project.build.testOutputDirectory}</value>
</property>
<property>
<name>org.jboss.byteman.transform.all</name>
<value>true</value>
</property>
</systemProperties>
</configuration>
<executions>
<execution>
<id>rejected-execution-test</id>
<goals><goal>test</goal></goals>
<configuration>
<systemProperties>
<property>
<name>org.jboss.byteman.transform.all</name>
<value>true</value>
</property>
<property>
<name>test.log.output</name>
<value>${project.build.directory}/surefire-reports</value>
</property>
<property>
<name>java.util.logging.manager</name>
<value>org.jboss.logmanager.LogManager</value>
</property>
</systemProperties>
<!-- add this to agent parameter list to enable debug ,prop:org.jboss.byteman.debug=true -->
<argLine>-Xbootclasspath/a:${settings.localRepository}/org/jboss/logmanager/${version.jboss-logmanager}/jboss-logmanager-${version.jboss-logmanager}.jar
-javaagent:${settings.localRepository}/org/jboss/byteman/byteman/${version.byteman}/byteman-${version.byteman}.jar=boot:${settings.localRepository}/org/jboss/byteman/byteman/${version.byteman}/byteman-${version.byteman}.jar,script:${project.build.testOutputDirectory}/org/jboss/msc/racecondition/RejectedExecutionTestCase.btm</argLine>
<includes>
<include>org/jboss/msc/racecondition/RejectedExecutionTestSuite.java</include>
</includes>
</configuration>
</execution>
<execution>
<id>removal-during-cycle-detection-test</id>
<goals><goal>test</goal></goals>
<configuration>
<systemProperties>
<property>
<name>test.log.output</name>
<value>${project.build.directory}/surefire-reports</value>
</property>
<property>
<name>java.util.logging.manager</name>
<value>org.jboss.logmanager.LogManager</value>
</property>
</systemProperties>
<includes>
<include>org/jboss/msc/racecondition/RemovalDuringCycleDetectionTest.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
Expand Down
64 changes: 64 additions & 0 deletions src/main/java/org/jboss/msc/service/ContainerShutdownListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.msc.service;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
final class ContainerShutdownListener {
@SuppressWarnings({ "UnusedDeclaration" })
private volatile int count = 1;
@SuppressWarnings({ "UnusedDeclaration" })
private volatile int done;
@SuppressWarnings({ "RawUseOfParameterizedType" })
private static final AtomicIntegerFieldUpdater<ContainerShutdownListener> countUpdater = AtomicIntegerFieldUpdater.newUpdater(ContainerShutdownListener.class, "count");
@SuppressWarnings({ "RawUseOfParameterizedType" })
private static final AtomicIntegerFieldUpdater<ContainerShutdownListener> doneUpdater = AtomicIntegerFieldUpdater.newUpdater(ContainerShutdownListener.class, "done");
private final Runnable callback;

ContainerShutdownListener(final Runnable callback) {
this.callback = callback;
}

final void controllerAlive() {
countUpdater.getAndIncrement(this);
}

final void controllerDied() {
tick();
}

final void done() {
if (doneUpdater.getAndSet(this, 1) == 0) {
tick();
}
}

private void tick() {
if (countUpdater.decrementAndGet(this) == 0) {
callback.run();
}
}
}
4 changes: 4 additions & 0 deletions src/main/java/org/jboss/msc/service/Dependency.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
* @author <a href="mailto:flavia.rainone@jboss.com">Flavia Rainone</a>
*/
interface Dependency extends Value<Object> {

/**
* Add a dependent to this dependency, establishing the dependency relation between this dependency and its
* dependent. This method must not be called under a lock.
Expand Down Expand Up @@ -94,4 +95,7 @@ interface Dependency extends Value<Object> {
* @return the controller, or {@code null} for none
*/
ServiceControllerImpl<?> getDependencyController();

Lockable getLock();

}
20 changes: 0 additions & 20 deletions src/main/java/org/jboss/msc/service/Dependent.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,6 @@ interface Dependent {
*/
void dependencyFailureCleared();

/**
* Notify this dependent that one of its transitive dependencies is unavailable (either uninstalled, or in
* {@link ServiceController.Mode#NEVER NEVER mode}).
* <p>
* New transitive dependencies that become unavailable after the notified one do not result in new {@code
* dependencyUnavailable} notifications, as the dependent will never receive two or more dependencyUnavailable calls
* in a row. A {@code dependencyUnavailable} notification is only invoked again to notify of newly found unavailable
* dependencies if all the previously unavailable dependencies have become {@link #transitiveDependencyAvailable()
* available}.
* <p> This method must not be called under a lock.
*/
void transitiveDependencyUnavailable();

/**
* Notify this dependent that all {@link #transitiveDependencyUnavailable() unavailable} transitive dependencies are
* now available (i.e., they are installed and will perform an attempt to start shortly).
* <p> This method must not be called under a lock.
*/
void transitiveDependencyAvailable();

/**
* Get the controller of this dependent.
*
Expand Down
123 changes: 123 additions & 0 deletions src/main/java/org/jboss/msc/service/Lockable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.msc.service;

import static java.lang.Thread.holdsLock;

/**
* Utility locking class requiring its intrinsic lock being held while calling its methods.
* This implementation heavily favors reader threads against writer threads.
*
* <p></p>
* Example of read lock usage:
* <pre>
* Lockable lock = ...
* synchronized (lock) {
* lock.acquireRead();
* }
* try {
* // ... do read-locked work here
* } finally {
* synchronized (lock) {
* lock.releaseRead();
* }
* }
* </pre>
* <p></p>
* Example of write lock usage:
* <pre>
* Lockable lock = ...
* synchronized (lock) {
* lock.acquireWrite();
* try {
* // ... do write-locked work here
* } finally {
* lock.releaseWrite();
* }
* }
* </pre>
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
abstract class Lockable {

/**
* Number of read locks being held.
*/
private int readLocksCount;

/**
* Acquires read lock. Must be called under the intrinsic lock.
* The read lock may be held simultaneously by multiple reader threads.
*/
final void acquireRead() {
assert holdsLock(this);
readLocksCount++;
}

/**
* Releases read lock. Must be called under the intrinsic lock.
* The write lock is exclusive.
*/
final void releaseRead() {
assert holdsLock(this);
if (--readLocksCount == 0) notify();
}

/**
* Acquires write lock. Must be called under the intrinsic lock.
* Write lock is available if and only if all read locks have been released.
*/
final void acquireWrite() {
assert holdsLock(this);
if (readLocksCount > 0) {
boolean intr = Thread.interrupted();
try {
do try {
wait();
} catch (InterruptedException ignored) {
intr = true;
} while (readLocksCount > 0);
} finally {
if (intr) Thread.currentThread().interrupt();
}
}
}

/**
* Releases write lock. Must be called under the intrinsic lock.
*/
final void releaseWrite() {
assert holdsLock(this);
notify();
}

/**
* Returns <code>true</code> iff write lock is effective <code>false</code> otherwise
* @return <code>true</code> if write locked <code>false</code> otherwise
*/
final boolean isWriteLocked() {
return holdsLock(this) && readLocksCount == 0;
}

}

0 comments on commit 38bbe12

Please sign in to comment.