diff options
author | Jean-Philippe Lesot <jplesot@google.com> | 2014-10-03 15:09:49 +0200 |
---|---|---|
committer | Jean-Philippe Lesot <jplesot@google.com> | 2014-10-03 16:24:53 +0200 |
commit | 9de22d42db7b6a12f8f98d9d5490c27c57b58c2d (patch) | |
tree | 69d8c7c175501178a2b95d3e2e6e997e5fe01c98 | |
parent | 2b4aafbc11d904ecf6a3926866bee09b768283c0 (diff) | |
download | toolchain_jack-9de22d42db7b6a12f8f98d9d5490c27c57b58c2d.zip toolchain_jack-9de22d42db7b6a12f8f98d9d5490c27c57b58c2d.tar.gz toolchain_jack-9de22d42db7b6a12f8f98d9d5490c27c57b58c2d.tar.bz2 |
Add dynamic @Synchronized support
Change-Id: I875b0902dc56a03699daa1eac95225655b3c658d
4 files changed, 70 insertions, 7 deletions
diff --git a/sched/src/com/android/sched/item/Synchronized.java b/sched/src/com/android/sched/item/Synchronized.java index a504f3f..694c852 100644 --- a/sched/src/com/android/sched/item/Synchronized.java +++ b/sched/src/com/android/sched/item/Synchronized.java @@ -23,9 +23,10 @@ import java.lang.annotation.Target; /** * Annotates a {@code Schedulable} and specifies that it has to run synchronized with itself, that - * one instance could run at most one at a time. + * one instance can run at most one at a time. A dynamic version can be declared by annotating a + * method with no parameter and that return true if that instance needs to be synchronized. */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target({ElementType.TYPE, ElementType.METHOD}) public @interface Synchronized { } diff --git a/sched/src/com/android/sched/marker/ManagedMarker.java b/sched/src/com/android/sched/marker/ManagedMarker.java index 7b75f11..fe309c3 100644 --- a/sched/src/com/android/sched/marker/ManagedMarker.java +++ b/sched/src/com/android/sched/marker/ManagedMarker.java @@ -252,7 +252,7 @@ public class ManagedMarker implements HasDescription { for (Class<? extends MarkerManager> marked : staticValidOn) { if (marked.isAssignableFrom(method.getParameterTypes()[0])) { - throw new MarkerNotConformException("Marker '" + name + "' cannot have both a static @'" + throw new MarkerNotConformException("Marker '" + name + "' cannot have both a static @" + ValidOn.class.getName() + " (on class '" + marker.getCanonicalName() + "') and a @" + DynamicValidOn.class.getName() + " (on method '" + method + "'"); } @@ -262,7 +262,7 @@ public class ManagedMarker implements HasDescription { if (dvo.validOn.isAssignableFrom(method.getParameterTypes()[0]) || method.getParameterTypes()[0].isAssignableFrom(dvo.validOn)) { throw new MarkerNotConformException("Marker '" + name - + "' could not have two @'" + DynamicValidOn.class.getName() + " ('" + method + + "' cannot have two @" + DynamicValidOn.class.getName() + " ('" + method + "' and '" + dvo.method + "')"); } } diff --git a/sched/src/com/android/sched/scheduler/ManagedSchedulable.java b/sched/src/com/android/sched/scheduler/ManagedSchedulable.java index 24dae82..f1edc8e 100644 --- a/sched/src/com/android/sched/scheduler/ManagedSchedulable.java +++ b/sched/src/com/android/sched/scheduler/ManagedSchedulable.java @@ -20,9 +20,17 @@ import com.android.sched.item.Component; import com.android.sched.item.Description; import com.android.sched.item.Items; import com.android.sched.item.Synchronized; +import com.android.sched.marker.MarkerNotConformException; import com.android.sched.schedulable.Schedulable; import com.android.sched.util.HasDescription; +import com.android.sched.util.log.LoggerFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.annotation.CheckForNull; import javax.annotation.Nonnull; /** @@ -30,6 +38,8 @@ import javax.annotation.Nonnull; */ public abstract class ManagedSchedulable implements HasDescription { @Nonnull + private static final Logger logger = LoggerFactory.getLogger(); + @Nonnull private final Class<? extends Schedulable> schedulable; // @Name @@ -42,6 +52,9 @@ public abstract class ManagedSchedulable implements HasDescription { // @Synchronized private boolean isSynchronized = false; + @CheckForNull + private Method dynamicIsSynchronized = null; + /** * Creates a new instance of {@link ManagedSchedulable} from a {@link Schedulable}. @@ -83,8 +96,27 @@ public abstract class ManagedSchedulable implements HasDescription { /** * @return if the schedulable is synchronized */ - public boolean isSynchronized() { - return isSynchronized; + public boolean isSynchronized(@Nonnull Schedulable schedulable) { + if (isSynchronized) { + return true; + } + + if (dynamicIsSynchronized != null) { + try { + return ((Boolean) dynamicIsSynchronized.invoke(schedulable)).booleanValue(); + } catch (IllegalArgumentException e) { + throw new AssertionError(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + logger.log(Level.WARNING, "Method '" + dynamicIsSynchronized + "' threw an exception", + e.getCause()); + + return false; + } + } + + return false; } /** @@ -109,5 +141,35 @@ public abstract class ManagedSchedulable implements HasDescription { Synchronized sync = cls.getAnnotation(Synchronized.class); isSynchronized = sync != null; + + for (Method method : cls.getMethods()) { + Synchronized dynamicSynchronizedOnAnnotation = method.getAnnotation(Synchronized.class); + + if (dynamicSynchronizedOnAnnotation != null) { + if (!method.getReturnType().equals(Boolean.TYPE)) { + throw new SchedulableNotConformException("Annotated method '" + method + "' with @" + + Synchronized.class.getSimpleName() + " must have a 'boolean' return type"); + } + + if (method.getParameterTypes().length != 0) { + throw new SchedulableNotConformException("Annotated method '" + method + "' with @" + + Synchronized.class.getSimpleName() + " must have no parameter"); + } + + if (isSynchronized) { + throw new SchedulableNotConformException("Schedulable '" + name + + "' cannot have both a static and a dynamic @" + Synchronized.class.getName() + + " (on class '" + cls.getCanonicalName() + "')"); + } + + if (dynamicIsSynchronized != null) { + throw new MarkerNotConformException("Schedulable '" + name + "' cannot have two @" + + Synchronized.class.getName() + " ('" + method + "' and '" + dynamicIsSynchronized + + "')"); + } + + dynamicIsSynchronized = method; + } + } } } diff --git a/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java b/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java index 9399c99..59105f3 100644 --- a/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java +++ b/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java @@ -89,7 +89,7 @@ public class MultiWorkersScheduleInstance<T extends Component> if (isSynchronizedManaged) { int idx = 0; for (PlanStep step : plan) { - if (step.getManagedSchedulable().isSynchronized()) { + if (step.getManagedSchedulable().isSynchronized(steps[idx].instance)) { syncs[idx] = new Synchronized(); } ++idx; |