Merge
This commit is contained in:
commit
445c56f3ea
@ -1068,14 +1068,14 @@ public class TreeMap<K,V>
|
|||||||
}
|
}
|
||||||
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
|
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
|
||||||
E toElement, boolean toInclusive) {
|
E toElement, boolean toInclusive) {
|
||||||
return new TreeSet<E>(m.subMap(fromElement, fromInclusive,
|
return new KeySet<E>(m.subMap(fromElement, fromInclusive,
|
||||||
toElement, toInclusive));
|
toElement, toInclusive));
|
||||||
}
|
}
|
||||||
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
|
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
|
||||||
return new TreeSet<E>(m.headMap(toElement, inclusive));
|
return new KeySet<E>(m.headMap(toElement, inclusive));
|
||||||
}
|
}
|
||||||
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
|
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
|
||||||
return new TreeSet<E>(m.tailMap(fromElement, inclusive));
|
return new KeySet<E>(m.tailMap(fromElement, inclusive));
|
||||||
}
|
}
|
||||||
public SortedSet<E> subSet(E fromElement, E toElement) {
|
public SortedSet<E> subSet(E fromElement, E toElement) {
|
||||||
return subSet(fromElement, true, toElement, false);
|
return subSet(fromElement, true, toElement, false);
|
||||||
@ -1087,7 +1087,7 @@ public class TreeMap<K,V>
|
|||||||
return tailSet(fromElement, true);
|
return tailSet(fromElement, true);
|
||||||
}
|
}
|
||||||
public NavigableSet<E> descendingSet() {
|
public NavigableSet<E> descendingSet() {
|
||||||
return new TreeSet(m.descendingMap());
|
return new KeySet(m.descendingMap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2394,15 +2394,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
|||||||
boolean fromInclusive,
|
boolean fromInclusive,
|
||||||
E toElement,
|
E toElement,
|
||||||
boolean toInclusive) {
|
boolean toInclusive) {
|
||||||
return new ConcurrentSkipListSet<E>
|
return new KeySet<E>(m.subMap(fromElement, fromInclusive,
|
||||||
(m.subMap(fromElement, fromInclusive,
|
toElement, toInclusive));
|
||||||
toElement, toInclusive));
|
|
||||||
}
|
}
|
||||||
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
|
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
|
||||||
return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
|
return new KeySet<E>(m.headMap(toElement, inclusive));
|
||||||
}
|
}
|
||||||
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
|
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
|
||||||
return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
|
return new KeySet<E>(m.tailMap(fromElement, inclusive));
|
||||||
}
|
}
|
||||||
public NavigableSet<E> subSet(E fromElement, E toElement) {
|
public NavigableSet<E> subSet(E fromElement, E toElement) {
|
||||||
return subSet(fromElement, true, toElement, false);
|
return subSet(fromElement, true, toElement, false);
|
||||||
@ -2414,7 +2413,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
|||||||
return tailSet(fromElement, true);
|
return tailSet(fromElement, true);
|
||||||
}
|
}
|
||||||
public NavigableSet<E> descendingSet() {
|
public NavigableSet<E> descendingSet() {
|
||||||
return new ConcurrentSkipListSet(m.descendingMap());
|
return new KeySet(m.descendingMap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +166,11 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
static final int SIGNAL = -1;
|
static final int SIGNAL = -1;
|
||||||
/** waitStatus value to indicate thread is waiting on condition */
|
/** waitStatus value to indicate thread is waiting on condition */
|
||||||
static final int CONDITION = -2;
|
static final int CONDITION = -2;
|
||||||
|
/**
|
||||||
|
* waitStatus value to indicate the next acquireShared should
|
||||||
|
* unconditionally propagate
|
||||||
|
*/
|
||||||
|
static final int PROPAGATE = -3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status field, taking on only the values:
|
* Status field, taking on only the values:
|
||||||
@ -180,10 +185,16 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
* Nodes never leave this state. In particular,
|
* Nodes never leave this state. In particular,
|
||||||
* a thread with cancelled node never again blocks.
|
* a thread with cancelled node never again blocks.
|
||||||
* CONDITION: This node is currently on a condition queue.
|
* CONDITION: This node is currently on a condition queue.
|
||||||
* It will not be used as a sync queue node until
|
* It will not be used as a sync queue node
|
||||||
* transferred. (Use of this value here
|
* until transferred, at which time the status
|
||||||
* has nothing to do with the other uses
|
* will be set to 0. (Use of this value here has
|
||||||
* of the field, but simplifies mechanics.)
|
* nothing to do with the other uses of the
|
||||||
|
* field, but simplifies mechanics.)
|
||||||
|
* PROPAGATE: A releaseShared should be propagated to other
|
||||||
|
* nodes. This is set (for head node only) in
|
||||||
|
* doReleaseShared to ensure propagation
|
||||||
|
* continues, even if other operations have
|
||||||
|
* since intervened.
|
||||||
* 0: None of the above
|
* 0: None of the above
|
||||||
*
|
*
|
||||||
* The values are arranged numerically to simplify use.
|
* The values are arranged numerically to simplify use.
|
||||||
@ -403,10 +414,13 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
*/
|
*/
|
||||||
private void unparkSuccessor(Node node) {
|
private void unparkSuccessor(Node node) {
|
||||||
/*
|
/*
|
||||||
* Try to clear status in anticipation of signalling. It is
|
* If status is negative (i.e., possibly needing signal) try
|
||||||
* OK if this fails or if status is changed by waiting thread.
|
* to clear in anticipation of signalling. It is OK if this
|
||||||
|
* fails or if status is changed by waiting thread.
|
||||||
*/
|
*/
|
||||||
compareAndSetWaitStatus(node, Node.SIGNAL, 0);
|
int ws = node.waitStatus;
|
||||||
|
if (ws < 0)
|
||||||
|
compareAndSetWaitStatus(node, ws, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Thread to unpark is held in successor, which is normally
|
* Thread to unpark is held in successor, which is normally
|
||||||
@ -425,24 +439,71 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
LockSupport.unpark(s.thread);
|
LockSupport.unpark(s.thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release action for shared mode -- signal successor and ensure
|
||||||
|
* propagation. (Note: For exclusive mode, release just amounts
|
||||||
|
* to calling unparkSuccessor of head if it needs signal.)
|
||||||
|
*/
|
||||||
|
private void doReleaseShared() {
|
||||||
|
/*
|
||||||
|
* Ensure that a release propagates, even if there are other
|
||||||
|
* in-progress acquires/releases. This proceeds in the usual
|
||||||
|
* way of trying to unparkSuccessor of head if it needs
|
||||||
|
* signal. But if it does not, status is set to PROPAGATE to
|
||||||
|
* ensure that upon release, propagation continues.
|
||||||
|
* Additionally, we must loop in case a new node is added
|
||||||
|
* while we are doing this. Also, unlike other uses of
|
||||||
|
* unparkSuccessor, we need to know if CAS to reset status
|
||||||
|
* fails, if so rechecking.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
Node h = head;
|
||||||
|
if (h != null && h != tail) {
|
||||||
|
int ws = h.waitStatus;
|
||||||
|
if (ws == Node.SIGNAL) {
|
||||||
|
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
|
||||||
|
continue; // loop to recheck cases
|
||||||
|
unparkSuccessor(h);
|
||||||
|
}
|
||||||
|
else if (ws == 0 &&
|
||||||
|
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
|
||||||
|
continue; // loop on failed CAS
|
||||||
|
}
|
||||||
|
if (h == head) // loop if head changed
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets head of queue, and checks if successor may be waiting
|
* Sets head of queue, and checks if successor may be waiting
|
||||||
* in shared mode, if so propagating if propagate > 0.
|
* in shared mode, if so propagating if either propagate > 0 or
|
||||||
|
* PROPAGATE status was set.
|
||||||
*
|
*
|
||||||
* @param pred the node holding waitStatus for node
|
|
||||||
* @param node the node
|
* @param node the node
|
||||||
* @param propagate the return value from a tryAcquireShared
|
* @param propagate the return value from a tryAcquireShared
|
||||||
*/
|
*/
|
||||||
private void setHeadAndPropagate(Node node, long propagate) {
|
private void setHeadAndPropagate(Node node, long propagate) {
|
||||||
|
Node h = head; // Record old head for check below
|
||||||
setHead(node);
|
setHead(node);
|
||||||
if (propagate > 0 && node.waitStatus != 0) {
|
/*
|
||||||
/*
|
* Try to signal next queued node if:
|
||||||
* Don't bother fully figuring out successor. If it
|
* Propagation was indicated by caller,
|
||||||
* looks null, call unparkSuccessor anyway to be safe.
|
* or was recorded (as h.waitStatus) by a previous operation
|
||||||
*/
|
* (note: this uses sign-check of waitStatus because
|
||||||
|
* PROPAGATE status may transition to SIGNAL.)
|
||||||
|
* and
|
||||||
|
* The next node is waiting in shared mode,
|
||||||
|
* or we don't know, because it appears null
|
||||||
|
*
|
||||||
|
* The conservatism in both of these checks may cause
|
||||||
|
* unnecessary wake-ups, but only when there are multiple
|
||||||
|
* racing acquires/releases, so most need signals now or soon
|
||||||
|
* anyway.
|
||||||
|
*/
|
||||||
|
if (propagate > 0 || h == null || h.waitStatus < 0) {
|
||||||
Node s = node.next;
|
Node s = node.next;
|
||||||
if (s == null || s.isShared())
|
if (s == null || s.isShared())
|
||||||
unparkSuccessor(node);
|
doReleaseShared();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,23 +526,27 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
while (pred.waitStatus > 0)
|
while (pred.waitStatus > 0)
|
||||||
node.prev = pred = pred.prev;
|
node.prev = pred = pred.prev;
|
||||||
|
|
||||||
// Getting this before setting waitStatus ensures staleness
|
// predNext is the apparent node to unsplice. CASes below will
|
||||||
|
// fail if not, in which case, we lost race vs another cancel
|
||||||
|
// or signal, so no further action is necessary.
|
||||||
Node predNext = pred.next;
|
Node predNext = pred.next;
|
||||||
|
|
||||||
// Can use unconditional write instead of CAS here
|
// Can use unconditional write instead of CAS here.
|
||||||
|
// After this atomic step, other Nodes can skip past us.
|
||||||
|
// Before, we are free of interference from other threads.
|
||||||
node.waitStatus = Node.CANCELLED;
|
node.waitStatus = Node.CANCELLED;
|
||||||
|
|
||||||
// If we are the tail, remove ourselves
|
// If we are the tail, remove ourselves.
|
||||||
if (node == tail && compareAndSetTail(node, pred)) {
|
if (node == tail && compareAndSetTail(node, pred)) {
|
||||||
compareAndSetNext(pred, predNext, null);
|
compareAndSetNext(pred, predNext, null);
|
||||||
} else {
|
} else {
|
||||||
// If "active" predecessor found...
|
// If successor needs signal, try to set pred's next-link
|
||||||
if (pred != head
|
// so it will get one. Otherwise wake it up to propagate.
|
||||||
&& (pred.waitStatus == Node.SIGNAL
|
int ws;
|
||||||
|| compareAndSetWaitStatus(pred, 0, Node.SIGNAL))
|
if (pred != head &&
|
||||||
&& pred.thread != null) {
|
((ws = pred.waitStatus) == Node.SIGNAL ||
|
||||||
|
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
|
||||||
// If successor is active, set predecessor's next link
|
pred.thread != null) {
|
||||||
Node next = node.next;
|
Node next = node.next;
|
||||||
if (next != null && next.waitStatus <= 0)
|
if (next != null && next.waitStatus <= 0)
|
||||||
compareAndSetNext(pred, predNext, next);
|
compareAndSetNext(pred, predNext, next);
|
||||||
@ -503,14 +568,14 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
* @return {@code true} if thread should block
|
* @return {@code true} if thread should block
|
||||||
*/
|
*/
|
||||||
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
|
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
|
||||||
int s = pred.waitStatus;
|
int ws = pred.waitStatus;
|
||||||
if (s < 0)
|
if (ws == Node.SIGNAL)
|
||||||
/*
|
/*
|
||||||
* This node has already set status asking a release
|
* This node has already set status asking a release
|
||||||
* to signal it, so it can safely park.
|
* to signal it, so it can safely park.
|
||||||
*/
|
*/
|
||||||
return true;
|
return true;
|
||||||
if (s > 0) {
|
if (ws > 0) {
|
||||||
/*
|
/*
|
||||||
* Predecessor was cancelled. Skip over predecessors and
|
* Predecessor was cancelled. Skip over predecessors and
|
||||||
* indicate retry.
|
* indicate retry.
|
||||||
@ -519,14 +584,14 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
node.prev = pred = pred.prev;
|
node.prev = pred = pred.prev;
|
||||||
} while (pred.waitStatus > 0);
|
} while (pred.waitStatus > 0);
|
||||||
pred.next = node;
|
pred.next = node;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
/*
|
/*
|
||||||
* Indicate that we need a signal, but don't park yet. Caller
|
* waitStatus must be 0 or PROPAGATE. Indicate that we
|
||||||
* will need to retry to make sure it cannot acquire before
|
* need a signal, but don't park yet. Caller will need to
|
||||||
* parking.
|
* retry to make sure it cannot acquire before parking.
|
||||||
*/
|
*/
|
||||||
compareAndSetWaitStatus(pred, 0, Node.SIGNAL);
|
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1046,9 +1111,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
*/
|
*/
|
||||||
public final boolean releaseShared(long arg) {
|
public final boolean releaseShared(long arg) {
|
||||||
if (tryReleaseShared(arg)) {
|
if (tryReleaseShared(arg)) {
|
||||||
Node h = head;
|
doReleaseShared();
|
||||||
if (h != null && h.waitStatus != 0)
|
|
||||||
unparkSuccessor(h);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1390,8 +1453,8 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||||||
* case the waitStatus can be transiently and harmlessly wrong).
|
* case the waitStatus can be transiently and harmlessly wrong).
|
||||||
*/
|
*/
|
||||||
Node p = enq(node);
|
Node p = enq(node);
|
||||||
int c = p.waitStatus;
|
int ws = p.waitStatus;
|
||||||
if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL))
|
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
|
||||||
LockSupport.unpark(node.thread);
|
LockSupport.unpark(node.thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -389,6 +389,11 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
static final int SIGNAL = -1;
|
static final int SIGNAL = -1;
|
||||||
/** waitStatus value to indicate thread is waiting on condition */
|
/** waitStatus value to indicate thread is waiting on condition */
|
||||||
static final int CONDITION = -2;
|
static final int CONDITION = -2;
|
||||||
|
/**
|
||||||
|
* waitStatus value to indicate the next acquireShared should
|
||||||
|
* unconditionally propagate
|
||||||
|
*/
|
||||||
|
static final int PROPAGATE = -3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status field, taking on only the values:
|
* Status field, taking on only the values:
|
||||||
@ -403,10 +408,16 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
* Nodes never leave this state. In particular,
|
* Nodes never leave this state. In particular,
|
||||||
* a thread with cancelled node never again blocks.
|
* a thread with cancelled node never again blocks.
|
||||||
* CONDITION: This node is currently on a condition queue.
|
* CONDITION: This node is currently on a condition queue.
|
||||||
* It will not be used as a sync queue node until
|
* It will not be used as a sync queue node
|
||||||
* transferred. (Use of this value here
|
* until transferred, at which time the status
|
||||||
* has nothing to do with the other uses
|
* will be set to 0. (Use of this value here has
|
||||||
* of the field, but simplifies mechanics.)
|
* nothing to do with the other uses of the
|
||||||
|
* field, but simplifies mechanics.)
|
||||||
|
* PROPAGATE: A releaseShared should be propagated to other
|
||||||
|
* nodes. This is set (for head node only) in
|
||||||
|
* doReleaseShared to ensure propagation
|
||||||
|
* continues, even if other operations have
|
||||||
|
* since intervened.
|
||||||
* 0: None of the above
|
* 0: None of the above
|
||||||
*
|
*
|
||||||
* The values are arranged numerically to simplify use.
|
* The values are arranged numerically to simplify use.
|
||||||
@ -626,10 +637,13 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
*/
|
*/
|
||||||
private void unparkSuccessor(Node node) {
|
private void unparkSuccessor(Node node) {
|
||||||
/*
|
/*
|
||||||
* Try to clear status in anticipation of signalling. It is
|
* If status is negative (i.e., possibly needing signal) try
|
||||||
* OK if this fails or if status is changed by waiting thread.
|
* to clear in anticipation of signalling. It is OK if this
|
||||||
|
* fails or if status is changed by waiting thread.
|
||||||
*/
|
*/
|
||||||
compareAndSetWaitStatus(node, Node.SIGNAL, 0);
|
int ws = node.waitStatus;
|
||||||
|
if (ws < 0)
|
||||||
|
compareAndSetWaitStatus(node, ws, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Thread to unpark is held in successor, which is normally
|
* Thread to unpark is held in successor, which is normally
|
||||||
@ -648,24 +662,71 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
LockSupport.unpark(s.thread);
|
LockSupport.unpark(s.thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release action for shared mode -- signal successor and ensure
|
||||||
|
* propagation. (Note: For exclusive mode, release just amounts
|
||||||
|
* to calling unparkSuccessor of head if it needs signal.)
|
||||||
|
*/
|
||||||
|
private void doReleaseShared() {
|
||||||
|
/*
|
||||||
|
* Ensure that a release propagates, even if there are other
|
||||||
|
* in-progress acquires/releases. This proceeds in the usual
|
||||||
|
* way of trying to unparkSuccessor of head if it needs
|
||||||
|
* signal. But if it does not, status is set to PROPAGATE to
|
||||||
|
* ensure that upon release, propagation continues.
|
||||||
|
* Additionally, we must loop in case a new node is added
|
||||||
|
* while we are doing this. Also, unlike other uses of
|
||||||
|
* unparkSuccessor, we need to know if CAS to reset status
|
||||||
|
* fails, if so rechecking.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
Node h = head;
|
||||||
|
if (h != null && h != tail) {
|
||||||
|
int ws = h.waitStatus;
|
||||||
|
if (ws == Node.SIGNAL) {
|
||||||
|
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
|
||||||
|
continue; // loop to recheck cases
|
||||||
|
unparkSuccessor(h);
|
||||||
|
}
|
||||||
|
else if (ws == 0 &&
|
||||||
|
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
|
||||||
|
continue; // loop on failed CAS
|
||||||
|
}
|
||||||
|
if (h == head) // loop if head changed
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets head of queue, and checks if successor may be waiting
|
* Sets head of queue, and checks if successor may be waiting
|
||||||
* in shared mode, if so propagating if propagate > 0.
|
* in shared mode, if so propagating if either propagate > 0 or
|
||||||
|
* PROPAGATE status was set.
|
||||||
*
|
*
|
||||||
* @param pred the node holding waitStatus for node
|
|
||||||
* @param node the node
|
* @param node the node
|
||||||
* @param propagate the return value from a tryAcquireShared
|
* @param propagate the return value from a tryAcquireShared
|
||||||
*/
|
*/
|
||||||
private void setHeadAndPropagate(Node node, int propagate) {
|
private void setHeadAndPropagate(Node node, int propagate) {
|
||||||
|
Node h = head; // Record old head for check below
|
||||||
setHead(node);
|
setHead(node);
|
||||||
if (propagate > 0 && node.waitStatus != 0) {
|
/*
|
||||||
/*
|
* Try to signal next queued node if:
|
||||||
* Don't bother fully figuring out successor. If it
|
* Propagation was indicated by caller,
|
||||||
* looks null, call unparkSuccessor anyway to be safe.
|
* or was recorded (as h.waitStatus) by a previous operation
|
||||||
*/
|
* (note: this uses sign-check of waitStatus because
|
||||||
|
* PROPAGATE status may transition to SIGNAL.)
|
||||||
|
* and
|
||||||
|
* The next node is waiting in shared mode,
|
||||||
|
* or we don't know, because it appears null
|
||||||
|
*
|
||||||
|
* The conservatism in both of these checks may cause
|
||||||
|
* unnecessary wake-ups, but only when there are multiple
|
||||||
|
* racing acquires/releases, so most need signals now or soon
|
||||||
|
* anyway.
|
||||||
|
*/
|
||||||
|
if (propagate > 0 || h == null || h.waitStatus < 0) {
|
||||||
Node s = node.next;
|
Node s = node.next;
|
||||||
if (s == null || s.isShared())
|
if (s == null || s.isShared())
|
||||||
unparkSuccessor(node);
|
doReleaseShared();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -688,23 +749,27 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
while (pred.waitStatus > 0)
|
while (pred.waitStatus > 0)
|
||||||
node.prev = pred = pred.prev;
|
node.prev = pred = pred.prev;
|
||||||
|
|
||||||
// Getting this before setting waitStatus ensures staleness
|
// predNext is the apparent node to unsplice. CASes below will
|
||||||
|
// fail if not, in which case, we lost race vs another cancel
|
||||||
|
// or signal, so no further action is necessary.
|
||||||
Node predNext = pred.next;
|
Node predNext = pred.next;
|
||||||
|
|
||||||
// Can use unconditional write instead of CAS here
|
// Can use unconditional write instead of CAS here.
|
||||||
|
// After this atomic step, other Nodes can skip past us.
|
||||||
|
// Before, we are free of interference from other threads.
|
||||||
node.waitStatus = Node.CANCELLED;
|
node.waitStatus = Node.CANCELLED;
|
||||||
|
|
||||||
// If we are the tail, remove ourselves
|
// If we are the tail, remove ourselves.
|
||||||
if (node == tail && compareAndSetTail(node, pred)) {
|
if (node == tail && compareAndSetTail(node, pred)) {
|
||||||
compareAndSetNext(pred, predNext, null);
|
compareAndSetNext(pred, predNext, null);
|
||||||
} else {
|
} else {
|
||||||
// If "active" predecessor found...
|
// If successor needs signal, try to set pred's next-link
|
||||||
if (pred != head
|
// so it will get one. Otherwise wake it up to propagate.
|
||||||
&& (pred.waitStatus == Node.SIGNAL
|
int ws;
|
||||||
|| compareAndSetWaitStatus(pred, 0, Node.SIGNAL))
|
if (pred != head &&
|
||||||
&& pred.thread != null) {
|
((ws = pred.waitStatus) == Node.SIGNAL ||
|
||||||
|
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
|
||||||
// If successor is active, set predecessor's next link
|
pred.thread != null) {
|
||||||
Node next = node.next;
|
Node next = node.next;
|
||||||
if (next != null && next.waitStatus <= 0)
|
if (next != null && next.waitStatus <= 0)
|
||||||
compareAndSetNext(pred, predNext, next);
|
compareAndSetNext(pred, predNext, next);
|
||||||
@ -726,14 +791,14 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
* @return {@code true} if thread should block
|
* @return {@code true} if thread should block
|
||||||
*/
|
*/
|
||||||
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
|
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
|
||||||
int s = pred.waitStatus;
|
int ws = pred.waitStatus;
|
||||||
if (s < 0)
|
if (ws == Node.SIGNAL)
|
||||||
/*
|
/*
|
||||||
* This node has already set status asking a release
|
* This node has already set status asking a release
|
||||||
* to signal it, so it can safely park.
|
* to signal it, so it can safely park.
|
||||||
*/
|
*/
|
||||||
return true;
|
return true;
|
||||||
if (s > 0) {
|
if (ws > 0) {
|
||||||
/*
|
/*
|
||||||
* Predecessor was cancelled. Skip over predecessors and
|
* Predecessor was cancelled. Skip over predecessors and
|
||||||
* indicate retry.
|
* indicate retry.
|
||||||
@ -742,14 +807,14 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
node.prev = pred = pred.prev;
|
node.prev = pred = pred.prev;
|
||||||
} while (pred.waitStatus > 0);
|
} while (pred.waitStatus > 0);
|
||||||
pred.next = node;
|
pred.next = node;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
/*
|
/*
|
||||||
* Indicate that we need a signal, but don't park yet. Caller
|
* waitStatus must be 0 or PROPAGATE. Indicate that we
|
||||||
* will need to retry to make sure it cannot acquire before
|
* need a signal, but don't park yet. Caller will need to
|
||||||
* parking.
|
* retry to make sure it cannot acquire before parking.
|
||||||
*/
|
*/
|
||||||
compareAndSetWaitStatus(pred, 0, Node.SIGNAL);
|
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1269,9 +1334,7 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
*/
|
*/
|
||||||
public final boolean releaseShared(int arg) {
|
public final boolean releaseShared(int arg) {
|
||||||
if (tryReleaseShared(arg)) {
|
if (tryReleaseShared(arg)) {
|
||||||
Node h = head;
|
doReleaseShared();
|
||||||
if (h != null && h.waitStatus != 0)
|
|
||||||
unparkSuccessor(h);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1613,8 +1676,8 @@ public abstract class AbstractQueuedSynchronizer
|
|||||||
* case the waitStatus can be transiently and harmlessly wrong).
|
* case the waitStatus can be transiently and harmlessly wrong).
|
||||||
*/
|
*/
|
||||||
Node p = enq(node);
|
Node p = enq(node);
|
||||||
int c = p.waitStatus;
|
int ws = p.waitStatus;
|
||||||
if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL))
|
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
|
||||||
LockSupport.unpark(node.thread);
|
LockSupport.unpark(node.thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
* Maintained as a ThreadLocal; cached in cachedHoldCounter
|
* Maintained as a ThreadLocal; cached in cachedHoldCounter
|
||||||
*/
|
*/
|
||||||
static final class HoldCounter {
|
static final class HoldCounter {
|
||||||
int count;
|
int count = 0;
|
||||||
// Use id, not reference, to avoid garbage retention
|
// Use id, not reference, to avoid garbage retention
|
||||||
final long tid = Thread.currentThread().getId();
|
final long tid = Thread.currentThread().getId();
|
||||||
}
|
}
|
||||||
@ -293,8 +293,9 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of read locks held by current thread.
|
* The number of reentrant read locks held by current thread.
|
||||||
* Initialized only in constructor and readObject.
|
* Initialized only in constructor and readObject.
|
||||||
|
* Removed whenever a thread's read hold count drops to 0.
|
||||||
*/
|
*/
|
||||||
private transient ThreadLocalHoldCounter readHolds;
|
private transient ThreadLocalHoldCounter readHolds;
|
||||||
|
|
||||||
@ -304,17 +305,35 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
* where the next thread to release is the last one to
|
* where the next thread to release is the last one to
|
||||||
* acquire. This is non-volatile since it is just used
|
* acquire. This is non-volatile since it is just used
|
||||||
* as a heuristic, and would be great for threads to cache.
|
* as a heuristic, and would be great for threads to cache.
|
||||||
|
*
|
||||||
|
* <p>Can outlive the Thread for which it is caching the read
|
||||||
|
* hold count, but avoids garbage retention by not retaining a
|
||||||
|
* reference to the Thread.
|
||||||
|
*
|
||||||
|
* <p>Accessed via a benign data race; relies on the memory
|
||||||
|
* model's final field and out-of-thin-air guarantees.
|
||||||
*/
|
*/
|
||||||
private transient HoldCounter cachedHoldCounter;
|
private transient HoldCounter cachedHoldCounter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* firstReader is the first thread to have acquired the read lock.
|
* firstReader is the first thread to have acquired the read lock.
|
||||||
* firstReaderHoldCount is firstReader's hold count.
|
* firstReaderHoldCount is firstReader's hold count.
|
||||||
* This allows tracking of read holds for uncontended read
|
*
|
||||||
|
* <p>More precisely, firstReader is the unique thread that last
|
||||||
|
* changed the shared count from 0 to 1, and has not released the
|
||||||
|
* read lock since then; null if there is no such thread.
|
||||||
|
*
|
||||||
|
* <p>Cannot cause garbage retention unless the thread terminated
|
||||||
|
* without relinquishing its read locks, since tryReleaseShared
|
||||||
|
* sets it to null.
|
||||||
|
*
|
||||||
|
* <p>Accessed via a benign data race; relies on the memory
|
||||||
|
* model's out-of-thin-air guarantees for references.
|
||||||
|
*
|
||||||
|
* <p>This allows tracking of read holds for uncontended read
|
||||||
* locks to be very cheap.
|
* locks to be very cheap.
|
||||||
*/
|
*/
|
||||||
private final static long INVALID_THREAD_ID = -1;
|
private transient Thread firstReader = null;
|
||||||
private transient long firstReader = INVALID_THREAD_ID;
|
|
||||||
private transient int firstReaderHoldCount;
|
private transient int firstReaderHoldCount;
|
||||||
|
|
||||||
Sync() {
|
Sync() {
|
||||||
@ -393,16 +412,16 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final boolean tryReleaseShared(int unused) {
|
protected final boolean tryReleaseShared(int unused) {
|
||||||
long tid = Thread.currentThread().getId();
|
Thread current = Thread.currentThread();
|
||||||
if (firstReader == tid) {
|
if (firstReader == current) {
|
||||||
// assert firstReaderHoldCount > 0;
|
// assert firstReaderHoldCount > 0;
|
||||||
if (firstReaderHoldCount == 1)
|
if (firstReaderHoldCount == 1)
|
||||||
firstReader = INVALID_THREAD_ID;
|
firstReader = null;
|
||||||
else
|
else
|
||||||
firstReaderHoldCount--;
|
firstReaderHoldCount--;
|
||||||
} else {
|
} else {
|
||||||
HoldCounter rh = cachedHoldCounter;
|
HoldCounter rh = cachedHoldCounter;
|
||||||
if (rh == null || rh.tid != tid)
|
if (rh == null || rh.tid != current.getId())
|
||||||
rh = readHolds.get();
|
rh = readHolds.get();
|
||||||
int count = rh.count;
|
int count = rh.count;
|
||||||
if (count <= 1) {
|
if (count <= 1) {
|
||||||
@ -416,6 +435,9 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
int c = getState();
|
int c = getState();
|
||||||
int nextc = c - SHARED_UNIT;
|
int nextc = c - SHARED_UNIT;
|
||||||
if (compareAndSetState(c, nextc))
|
if (compareAndSetState(c, nextc))
|
||||||
|
// Releasing the read lock has no effect on readers,
|
||||||
|
// but it may allow waiting writers to proceed if
|
||||||
|
// both read and write locks are now free.
|
||||||
return nextc == 0;
|
return nextc == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -450,15 +472,14 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
if (!readerShouldBlock() &&
|
if (!readerShouldBlock() &&
|
||||||
r < MAX_COUNT &&
|
r < MAX_COUNT &&
|
||||||
compareAndSetState(c, c + SHARED_UNIT)) {
|
compareAndSetState(c, c + SHARED_UNIT)) {
|
||||||
long tid = current.getId();
|
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
firstReader = tid;
|
firstReader = current;
|
||||||
firstReaderHoldCount = 1;
|
firstReaderHoldCount = 1;
|
||||||
} else if (firstReader == tid) {
|
} else if (firstReader == current) {
|
||||||
firstReaderHoldCount++;
|
firstReaderHoldCount++;
|
||||||
} else {
|
} else {
|
||||||
HoldCounter rh = cachedHoldCounter;
|
HoldCounter rh = cachedHoldCounter;
|
||||||
if (rh == null || rh.tid != tid)
|
if (rh == null || rh.tid != current.getId())
|
||||||
cachedHoldCounter = rh = readHolds.get();
|
cachedHoldCounter = rh = readHolds.get();
|
||||||
else if (rh.count == 0)
|
else if (rh.count == 0)
|
||||||
readHolds.set(rh);
|
readHolds.set(rh);
|
||||||
@ -485,19 +506,17 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
int c = getState();
|
int c = getState();
|
||||||
if (exclusiveCount(c) != 0) {
|
if (exclusiveCount(c) != 0) {
|
||||||
if (getExclusiveOwnerThread() != current)
|
if (getExclusiveOwnerThread() != current)
|
||||||
//if (removeNeeded) readHolds.remove();
|
|
||||||
return -1;
|
return -1;
|
||||||
// else we hold the exclusive lock; blocking here
|
// else we hold the exclusive lock; blocking here
|
||||||
// would cause deadlock.
|
// would cause deadlock.
|
||||||
} else if (readerShouldBlock()) {
|
} else if (readerShouldBlock()) {
|
||||||
// Make sure we're not acquiring read lock reentrantly
|
// Make sure we're not acquiring read lock reentrantly
|
||||||
long tid = current.getId();
|
if (firstReader == current) {
|
||||||
if (firstReader == tid) {
|
|
||||||
// assert firstReaderHoldCount > 0;
|
// assert firstReaderHoldCount > 0;
|
||||||
} else {
|
} else {
|
||||||
if (rh == null) {
|
if (rh == null) {
|
||||||
rh = cachedHoldCounter;
|
rh = cachedHoldCounter;
|
||||||
if (rh == null || rh.tid != tid) {
|
if (rh == null || rh.tid != current.getId()) {
|
||||||
rh = readHolds.get();
|
rh = readHolds.get();
|
||||||
if (rh.count == 0)
|
if (rh.count == 0)
|
||||||
readHolds.remove();
|
readHolds.remove();
|
||||||
@ -510,25 +529,20 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
if (sharedCount(c) == MAX_COUNT)
|
if (sharedCount(c) == MAX_COUNT)
|
||||||
throw new Error("Maximum lock count exceeded");
|
throw new Error("Maximum lock count exceeded");
|
||||||
if (compareAndSetState(c, c + SHARED_UNIT)) {
|
if (compareAndSetState(c, c + SHARED_UNIT)) {
|
||||||
long tid = current.getId();
|
|
||||||
if (sharedCount(c) == 0) {
|
if (sharedCount(c) == 0) {
|
||||||
firstReader = tid;
|
firstReader = current;
|
||||||
firstReaderHoldCount = 1;
|
firstReaderHoldCount = 1;
|
||||||
} else if (firstReader == tid) {
|
} else if (firstReader == current) {
|
||||||
firstReaderHoldCount++;
|
firstReaderHoldCount++;
|
||||||
} else {
|
} else {
|
||||||
if (rh == null) {
|
if (rh == null)
|
||||||
rh = cachedHoldCounter;
|
rh = cachedHoldCounter;
|
||||||
if (rh != null && rh.tid == tid) {
|
if (rh == null || rh.tid != current.getId())
|
||||||
if (rh.count == 0)
|
rh = readHolds.get();
|
||||||
readHolds.set(rh);
|
else if (rh.count == 0)
|
||||||
} else {
|
|
||||||
rh = readHolds.get();
|
|
||||||
}
|
|
||||||
} else if (rh.count == 0)
|
|
||||||
readHolds.set(rh);
|
readHolds.set(rh);
|
||||||
cachedHoldCounter = rh; // cache for release
|
|
||||||
rh.count++;
|
rh.count++;
|
||||||
|
cachedHoldCounter = rh; // cache for release
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -572,15 +586,14 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
if (r == MAX_COUNT)
|
if (r == MAX_COUNT)
|
||||||
throw new Error("Maximum lock count exceeded");
|
throw new Error("Maximum lock count exceeded");
|
||||||
if (compareAndSetState(c, c + SHARED_UNIT)) {
|
if (compareAndSetState(c, c + SHARED_UNIT)) {
|
||||||
long tid = current.getId();
|
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
firstReader = tid;
|
firstReader = current;
|
||||||
firstReaderHoldCount = 1;
|
firstReaderHoldCount = 1;
|
||||||
} else if (firstReader == tid) {
|
} else if (firstReader == current) {
|
||||||
firstReaderHoldCount++;
|
firstReaderHoldCount++;
|
||||||
} else {
|
} else {
|
||||||
HoldCounter rh = cachedHoldCounter;
|
HoldCounter rh = cachedHoldCounter;
|
||||||
if (rh == null || rh.tid != tid)
|
if (rh == null || rh.tid != current.getId())
|
||||||
cachedHoldCounter = rh = readHolds.get();
|
cachedHoldCounter = rh = readHolds.get();
|
||||||
else if (rh.count == 0)
|
else if (rh.count == 0)
|
||||||
readHolds.set(rh);
|
readHolds.set(rh);
|
||||||
@ -626,12 +639,12 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
if (getReadLockCount() == 0)
|
if (getReadLockCount() == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
long tid = Thread.currentThread().getId();
|
Thread current = Thread.currentThread();
|
||||||
if (firstReader == tid)
|
if (firstReader == current)
|
||||||
return firstReaderHoldCount;
|
return firstReaderHoldCount;
|
||||||
|
|
||||||
HoldCounter rh = cachedHoldCounter;
|
HoldCounter rh = cachedHoldCounter;
|
||||||
if (rh != null && rh.tid == tid)
|
if (rh != null && rh.tid == current.getId())
|
||||||
return rh.count;
|
return rh.count;
|
||||||
|
|
||||||
int count = readHolds.get().count;
|
int count = readHolds.get().count;
|
||||||
@ -647,7 +660,6 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
|
|||||||
throws java.io.IOException, ClassNotFoundException {
|
throws java.io.IOException, ClassNotFoundException {
|
||||||
s.defaultReadObject();
|
s.defaultReadObject();
|
||||||
readHolds = new ThreadLocalHoldCounter();
|
readHolds = new ThreadLocalHoldCounter();
|
||||||
firstReader = INVALID_THREAD_ID;
|
|
||||||
setState(0); // reset to unlocked state
|
setState(0); // reset to unlocked state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,6 @@ public class DefaultProxySelector extends ProxySelector {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static boolean hasSystemProxies = false;
|
private static boolean hasSystemProxies = false;
|
||||||
private static Properties defprops = new Properties();
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final String key = "java.net.useSystemProxies";
|
final String key = "java.net.useSystemProxies";
|
||||||
@ -107,6 +106,9 @@ public class DefaultProxySelector extends ProxySelector {
|
|||||||
RegexpPool hostsPool;
|
RegexpPool hostsPool;
|
||||||
String property;
|
String property;
|
||||||
|
|
||||||
|
static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null);
|
||||||
|
static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null);
|
||||||
|
|
||||||
NonProxyInfo(String p, String s, RegexpPool pool) {
|
NonProxyInfo(String p, String s, RegexpPool pool) {
|
||||||
property = p;
|
property = p;
|
||||||
hostsSource = s;
|
hostsSource = s;
|
||||||
@ -114,8 +116,6 @@ public class DefaultProxySelector extends ProxySelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null);
|
|
||||||
private static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* select() method. Where all the hard work is done.
|
* select() method. Where all the hard work is done.
|
||||||
@ -175,13 +175,13 @@ public class DefaultProxySelector extends ProxySelector {
|
|||||||
NonProxyInfo pinfo = null;
|
NonProxyInfo pinfo = null;
|
||||||
|
|
||||||
if ("http".equalsIgnoreCase(protocol)) {
|
if ("http".equalsIgnoreCase(protocol)) {
|
||||||
pinfo = httpNonProxyInfo;
|
pinfo = NonProxyInfo.httpNonProxyInfo;
|
||||||
} else if ("https".equalsIgnoreCase(protocol)) {
|
} else if ("https".equalsIgnoreCase(protocol)) {
|
||||||
// HTTPS uses the same property as HTTP, for backward
|
// HTTPS uses the same property as HTTP, for backward
|
||||||
// compatibility
|
// compatibility
|
||||||
pinfo = httpNonProxyInfo;
|
pinfo = NonProxyInfo.httpNonProxyInfo;
|
||||||
} else if ("ftp".equalsIgnoreCase(protocol)) {
|
} else if ("ftp".equalsIgnoreCase(protocol)) {
|
||||||
pinfo = ftpNonProxyInfo;
|
pinfo = NonProxyInfo.ftpNonProxyInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -334,7 +334,6 @@ public class DefaultProxySelector extends ProxySelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1");
|
|
||||||
private boolean isLoopback(String host) {
|
private boolean isLoopback(String host) {
|
||||||
if (host == null || host.length() == 0)
|
if (host == null || host.length() == 0)
|
||||||
return false;
|
return false;
|
||||||
@ -364,6 +363,7 @@ public class DefaultProxySelector extends ProxySelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (host.endsWith(":1")) {
|
if (host.endsWith(":1")) {
|
||||||
|
final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1");
|
||||||
return p6.matcher(host).matches();
|
return p6.matcher(host).matches();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -54,8 +54,8 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
"If keystore is not password protected, then -storepass and -keypass must not be specified"},
|
"If keystore is not password protected, then -storepass and -keypass must not be specified"},
|
||||||
{"Usage: jarsigner [options] jar-file alias",
|
{"Usage: jarsigner [options] jar-file alias",
|
||||||
"Usage: jarsigner [options] jar-file alias"},
|
"Usage: jarsigner [options] jar-file alias"},
|
||||||
{" jarsigner -verify [options] jar-file",
|
{" jarsigner -verify [options] jar-file [alias...]",
|
||||||
" jarsigner -verify [options] jar-file"},
|
" jarsigner -verify [options] jar-file [alias...]"},
|
||||||
{"[-keystore <url>] keystore location",
|
{"[-keystore <url>] keystore location",
|
||||||
"[-keystore <url>] keystore location"},
|
"[-keystore <url>] keystore location"},
|
||||||
{"[-storepass <password>] password for keystore integrity",
|
{"[-storepass <password>] password for keystore integrity",
|
||||||
@ -64,6 +64,8 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
"[-storetype <type>] keystore type"},
|
"[-storetype <type>] keystore type"},
|
||||||
{"[-keypass <password>] password for private key (if different)",
|
{"[-keypass <password>] password for private key (if different)",
|
||||||
"[-keypass <password>] password for private key (if different)"},
|
"[-keypass <password>] password for private key (if different)"},
|
||||||
|
{"[-certchain <file>] name of alternative certchain file",
|
||||||
|
"[-certchain <file>] name of alternative certchain file"},
|
||||||
{"[-sigfile <file>] name of .SF/.DSA file",
|
{"[-sigfile <file>] name of .SF/.DSA file",
|
||||||
"[-sigfile <file>] name of .SF/.DSA file"},
|
"[-sigfile <file>] name of .SF/.DSA file"},
|
||||||
{"[-signedjar <file>] name of signed JAR file",
|
{"[-signedjar <file>] name of signed JAR file",
|
||||||
@ -74,8 +76,10 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
"[-sigalg <algorithm>] name of signature algorithm"},
|
"[-sigalg <algorithm>] name of signature algorithm"},
|
||||||
{"[-verify] verify a signed JAR file",
|
{"[-verify] verify a signed JAR file",
|
||||||
"[-verify] verify a signed JAR file"},
|
"[-verify] verify a signed JAR file"},
|
||||||
{"[-verbose] verbose output when signing/verifying",
|
{"[-verbose[:suboptions]] verbose output when signing/verifying.",
|
||||||
"[-verbose] verbose output when signing/verifying"},
|
"[-verbose[:suboptions]] verbose output when signing/verifying."},
|
||||||
|
{" suboptions can be all, grouped or summary",
|
||||||
|
" suboptions can be all, grouped or summary"},
|
||||||
{"[-certs] display certificates when verbose and verifying",
|
{"[-certs] display certificates when verbose and verifying",
|
||||||
"[-certs] display certificates when verbose and verifying"},
|
"[-certs] display certificates when verbose and verifying"},
|
||||||
{"[-tsa <url>] location of the Timestamping Authority",
|
{"[-tsa <url>] location of the Timestamping Authority",
|
||||||
@ -98,10 +102,22 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
"[-providerClass <class> name of cryptographic service provider's"},
|
"[-providerClass <class> name of cryptographic service provider's"},
|
||||||
{" [-providerArg <arg>]] ... master class file and constructor argument",
|
{" [-providerArg <arg>]] ... master class file and constructor argument",
|
||||||
" [-providerArg <arg>]] ... master class file and constructor argument"},
|
" [-providerArg <arg>]] ... master class file and constructor argument"},
|
||||||
|
{"[-strict] treat warnings as errors",
|
||||||
|
"[-strict] treat warnings as errors"},
|
||||||
|
{"Option lacks argument", "Option lacks argument"},
|
||||||
|
{"Please type jarsigner -help for usage", "Please type jarsigner -help for usage"},
|
||||||
|
{"Please specify jarfile name", "Please specify jarfile name"},
|
||||||
|
{"Please specify alias name", "Please specify alias name"},
|
||||||
|
{"Only one alias can be specified", "Only one alias can be specified"},
|
||||||
|
{"This jar contains signed entries which is not signed by the specified alias(es).",
|
||||||
|
"This jar contains signed entries which is not signed by the specified alias(es)."},
|
||||||
|
{"This jar contains signed entries that's not signed by alias in this keystore.",
|
||||||
|
"This jar contains signed entries that's not signed by alias in this keystore."},
|
||||||
{"s", "s"},
|
{"s", "s"},
|
||||||
{"m", "m"},
|
{"m", "m"},
|
||||||
{"k", "k"},
|
{"k", "k"},
|
||||||
{"i", "i"},
|
{"i", "i"},
|
||||||
|
{"(and %d more)", "(and %d more)"},
|
||||||
{" s = signature was verified ",
|
{" s = signature was verified ",
|
||||||
" s = signature was verified "},
|
" s = signature was verified "},
|
||||||
{" m = entry is listed in manifest",
|
{" m = entry is listed in manifest",
|
||||||
@ -110,7 +126,11 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
" k = at least one certificate was found in keystore"},
|
" k = at least one certificate was found in keystore"},
|
||||||
{" i = at least one certificate was found in identity scope",
|
{" i = at least one certificate was found in identity scope",
|
||||||
" i = at least one certificate was found in identity scope"},
|
" i = at least one certificate was found in identity scope"},
|
||||||
|
{" X = not signed by specified alias(es)",
|
||||||
|
" X = not signed by specified alias(es)"},
|
||||||
{"no manifest.", "no manifest."},
|
{"no manifest.", "no manifest."},
|
||||||
|
{"(Signature related entries)","(Signature related entries)"},
|
||||||
|
{"(Unsigned entries)", "(Unsigned entries)"},
|
||||||
{"jar is unsigned. (signatures missing or not parsable)",
|
{"jar is unsigned. (signatures missing or not parsable)",
|
||||||
"jar is unsigned. (signatures missing or not parsable)"},
|
"jar is unsigned. (signatures missing or not parsable)"},
|
||||||
{"jar verified.", "jar verified."},
|
{"jar verified.", "jar verified."},
|
||||||
@ -134,6 +154,12 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
"unable to instantiate keystore class: "},
|
"unable to instantiate keystore class: "},
|
||||||
{"Certificate chain not found for: alias. alias must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.",
|
{"Certificate chain not found for: alias. alias must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.",
|
||||||
"Certificate chain not found for: {0}. {1} must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain."},
|
"Certificate chain not found for: {0}. {1} must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain."},
|
||||||
|
{"File specified by -certchain does not exist",
|
||||||
|
"File specified by -certchain does not exist"},
|
||||||
|
{"Cannot restore certchain from file specified",
|
||||||
|
"Cannot restore certchain from file specified"},
|
||||||
|
{"Certificate chain not found in the file specified.",
|
||||||
|
"Certificate chain not found in the file specified."},
|
||||||
{"found non-X.509 certificate in signer's chain",
|
{"found non-X.509 certificate in signer's chain",
|
||||||
"found non-X.509 certificate in signer's chain"},
|
"found non-X.509 certificate in signer's chain"},
|
||||||
{"incomplete certificate chain", "incomplete certificate chain"},
|
{"incomplete certificate chain", "incomplete certificate chain"},
|
||||||
@ -149,6 +175,7 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
{"certificate is not valid until",
|
{"certificate is not valid until",
|
||||||
"certificate is not valid until {0}"},
|
"certificate is not valid until {0}"},
|
||||||
{"certificate will expire on", "certificate will expire on {0}"},
|
{"certificate will expire on", "certificate will expire on {0}"},
|
||||||
|
{"[CertPath not validated: ", "[CertPath not validated: "},
|
||||||
{"requesting a signature timestamp",
|
{"requesting a signature timestamp",
|
||||||
"requesting a signature timestamp"},
|
"requesting a signature timestamp"},
|
||||||
{"TSA location: ", "TSA location: "},
|
{"TSA location: ", "TSA location: "},
|
||||||
@ -189,14 +216,18 @@ public class JarSignerResources extends java.util.ListResourceBundle {
|
|||||||
"The signer certificate's ExtendedKeyUsage extension doesn't allow code signing."},
|
"The signer certificate's ExtendedKeyUsage extension doesn't allow code signing."},
|
||||||
{"The signer certificate's NetscapeCertType extension doesn't allow code signing.",
|
{"The signer certificate's NetscapeCertType extension doesn't allow code signing.",
|
||||||
"The signer certificate's NetscapeCertType extension doesn't allow code signing."},
|
"The signer certificate's NetscapeCertType extension doesn't allow code signing."},
|
||||||
{"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing.",
|
{"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing.",
|
||||||
"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing."},
|
"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing."},
|
||||||
{"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.",
|
{"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.",
|
||||||
"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing."},
|
"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing."},
|
||||||
{"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.",
|
{"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.",
|
||||||
"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing."},
|
"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing."},
|
||||||
{"[{0} extension does not support code signing]",
|
{"[{0} extension does not support code signing]",
|
||||||
"[{0} extension does not support code signing]"},
|
"[{0} extension does not support code signing]"},
|
||||||
|
{"The signer's certificate chain is not validated.",
|
||||||
|
"The signer's certificate chain is not validated."},
|
||||||
|
{"This jar contains entries whose certificate chain is not validated.",
|
||||||
|
"This jar contains entries whose certificate chain is not validated."},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3108,7 +3108,7 @@ public final class KeyTool {
|
|||||||
/**
|
/**
|
||||||
* Returns the keystore with the configured CA certificates.
|
* Returns the keystore with the configured CA certificates.
|
||||||
*/
|
*/
|
||||||
private KeyStore getCacertsKeyStore()
|
public static KeyStore getCacertsKeyStore()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
String sep = File.separator;
|
String sep = File.separator;
|
||||||
|
@ -555,6 +555,7 @@ public class MOAT {
|
|||||||
|
|
||||||
NavigableMap<Integer,Integer> nm =
|
NavigableMap<Integer,Integer> nm =
|
||||||
(NavigableMap<Integer,Integer>) m;
|
(NavigableMap<Integer,Integer>) m;
|
||||||
|
testNavigableMapRemovers(nm);
|
||||||
testNavigableMap(nm);
|
testNavigableMap(nm);
|
||||||
testNavigableMap(nm.headMap(6, false));
|
testNavigableMap(nm.headMap(6, false));
|
||||||
testNavigableMap(nm.headMap(5, true));
|
testNavigableMap(nm.headMap(5, true));
|
||||||
@ -742,6 +743,97 @@ public class MOAT {
|
|||||||
equal(it.next(), expected);
|
equal(it.next(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void equalMaps(Map m1, Map m2) {
|
||||||
|
equal(m1, m2);
|
||||||
|
equal(m2, m1);
|
||||||
|
equal(m1.size(), m2.size());
|
||||||
|
equal(m1.isEmpty(), m2.isEmpty());
|
||||||
|
equal(m1.toString(), m2.toString());
|
||||||
|
check(Arrays.equals(m1.entrySet().toArray(), m2.entrySet().toArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
static void testNavigableMapRemovers(NavigableMap m)
|
||||||
|
{
|
||||||
|
final Map emptyMap = new HashMap();
|
||||||
|
|
||||||
|
final Map singletonMap = new HashMap();
|
||||||
|
singletonMap.put(1, 2);
|
||||||
|
|
||||||
|
abstract class NavigableMapView {
|
||||||
|
abstract NavigableMap view(NavigableMap m);
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigableMapView[] views = {
|
||||||
|
new NavigableMapView() { NavigableMap view(NavigableMap m) {
|
||||||
|
return m; }},
|
||||||
|
new NavigableMapView() { NavigableMap view(NavigableMap m) {
|
||||||
|
return m.headMap(99, true); }},
|
||||||
|
new NavigableMapView() { NavigableMap view(NavigableMap m) {
|
||||||
|
return m.tailMap(-99, false); }},
|
||||||
|
new NavigableMapView() { NavigableMap view(NavigableMap m) {
|
||||||
|
return m.subMap(-99, true, 99, false); }},
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract class Remover {
|
||||||
|
abstract void remove(NavigableMap m, Object k, Object v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Remover[] removers = {
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
equal(m.remove(k), v); }},
|
||||||
|
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
equal(m.descendingMap().remove(k), v); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
equal(m.descendingMap().headMap(-86, false).remove(k), v); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
equal(m.descendingMap().tailMap(86, true).remove(k), v); }},
|
||||||
|
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
equal(m.headMap(86, true).remove(k), v); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
equal(m.tailMap(-86, true).remove(k), v); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
equal(m.subMap(-86, false, 86, true).remove(k), v); }},
|
||||||
|
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.keySet().remove(k)); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.navigableKeySet().remove(k)); }},
|
||||||
|
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.navigableKeySet().headSet(86, true).remove(k)); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.navigableKeySet().tailSet(-86, false).remove(k)); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.navigableKeySet().subSet(-86, true, 86, false)
|
||||||
|
.remove(k)); }},
|
||||||
|
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.descendingKeySet().headSet(-86, false).remove(k)); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.descendingKeySet().tailSet(86, true).remove(k)); }},
|
||||||
|
new Remover() { void remove(NavigableMap m, Object k, Object v) {
|
||||||
|
check(m.descendingKeySet().subSet(86, true, -86, false)
|
||||||
|
.remove(k)); }},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (NavigableMapView view : views) {
|
||||||
|
for (Remover remover : removers) {
|
||||||
|
try {
|
||||||
|
m.clear();
|
||||||
|
equalMaps(m, emptyMap);
|
||||||
|
equal(m.put(1, 2), null);
|
||||||
|
equalMaps(m, singletonMap);
|
||||||
|
NavigableMap v = view.view(m);
|
||||||
|
remover.remove(v, 1, 2);
|
||||||
|
equalMaps(m, emptyMap);
|
||||||
|
} catch (Throwable t) { unexpected(t); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void testNavigableMap(NavigableMap<Integer,Integer> m)
|
private static void testNavigableMap(NavigableMap<Integer,Integer> m)
|
||||||
{
|
{
|
||||||
clear(m);
|
clear(m);
|
||||||
|
116
jdk/test/java/util/concurrent/Semaphore/RacingReleases.java
Normal file
116
jdk/test/java/util/concurrent/Semaphore/RacingReleases.java
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code 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 General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is available under and governed by the GNU General Public
|
||||||
|
* License version 2 only, as published by the Free Software Foundation.
|
||||||
|
* However, the following notice accompanied the original version of this
|
||||||
|
* file:
|
||||||
|
*
|
||||||
|
* Written by Doug Lea with assistance from members of JCP JSR-166
|
||||||
|
* Expert Group and released to the public domain, as explained at
|
||||||
|
* http://creativecommons.org/licenses/publicdomain
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6801020 6803402
|
||||||
|
* @summary Try to tickle race conditions in
|
||||||
|
* AbstractQueuedSynchronizer "shared" code
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
public class RacingReleases {
|
||||||
|
|
||||||
|
/** Increase this for better chance of tickling races */
|
||||||
|
static final int iterations = 1000;
|
||||||
|
|
||||||
|
public static void test(final boolean fair,
|
||||||
|
final boolean interruptibly)
|
||||||
|
throws Throwable {
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
final Semaphore sem = new Semaphore(0, fair);
|
||||||
|
final Throwable[] badness = new Throwable[1];
|
||||||
|
Runnable blocker = interruptibly ?
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
sem.acquire();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
badness[0] = t;
|
||||||
|
throw new Error(t);
|
||||||
|
}}}
|
||||||
|
:
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
sem.acquireUninterruptibly();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
badness[0] = t;
|
||||||
|
throw new Error(t);
|
||||||
|
}}};
|
||||||
|
|
||||||
|
Thread b1 = new Thread(blocker);
|
||||||
|
Thread b2 = new Thread(blocker);
|
||||||
|
Runnable signaller = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
sem.release();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
badness[0] = t;
|
||||||
|
throw new Error(t);
|
||||||
|
}}};
|
||||||
|
Thread s1 = new Thread(signaller);
|
||||||
|
Thread s2 = new Thread(signaller);
|
||||||
|
Thread[] threads = { b1, b2, s1, s2 };
|
||||||
|
java.util.Collections.shuffle(java.util.Arrays.asList(threads));
|
||||||
|
for (Thread thread : threads)
|
||||||
|
thread.start();
|
||||||
|
for (Thread thread : threads) {
|
||||||
|
thread.join(60 * 1000);
|
||||||
|
if (thread.isAlive())
|
||||||
|
throw new Error
|
||||||
|
(String.format
|
||||||
|
("Semaphore stuck: permits %d, thread waiting %s%n",
|
||||||
|
sem.availablePermits(),
|
||||||
|
sem.hasQueuedThreads() ? "true" : "false"));
|
||||||
|
}
|
||||||
|
if (badness[0] != null)
|
||||||
|
throw new Error(badness[0]);
|
||||||
|
if (sem.availablePermits() != 0)
|
||||||
|
throw new Error(String.valueOf(sem.availablePermits()));
|
||||||
|
if (sem.hasQueuedThreads())
|
||||||
|
throw new Error(String.valueOf(sem.hasQueuedThreads()));
|
||||||
|
if (sem.getQueueLength() != 0)
|
||||||
|
throw new Error(String.valueOf(sem.getQueueLength()));
|
||||||
|
if (sem.isFair() != fair)
|
||||||
|
throw new Error(String.valueOf(sem.isFair()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
for (boolean fair : new boolean[] { true, false })
|
||||||
|
for (boolean interruptibly : new boolean[] { true, false })
|
||||||
|
test(fair, interruptibly);
|
||||||
|
}
|
||||||
|
}
|
200
jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh
Normal file
200
jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
#
|
||||||
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License version 2 only, as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This code 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 General Public License
|
||||||
|
# version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
# accompanied this code).
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License version
|
||||||
|
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
# have any questions.
|
||||||
|
#
|
||||||
|
|
||||||
|
# @test
|
||||||
|
# @bug 6802846
|
||||||
|
# @summary jarsigner needs enhanced cert validation(options)
|
||||||
|
#
|
||||||
|
# @run shell concise_jarsigner.sh
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ "${TESTJAVA}" = "" ] ; then
|
||||||
|
JAVAC_CMD=`which javac`
|
||||||
|
TESTJAVA=`dirname $JAVAC_CMD`/..
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set platform-dependent variables
|
||||||
|
OS=`uname -s`
|
||||||
|
case "$OS" in
|
||||||
|
Windows_* )
|
||||||
|
FS="\\"
|
||||||
|
;;
|
||||||
|
* )
|
||||||
|
FS="/"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore js.jks"
|
||||||
|
JAR=$TESTJAVA${FS}bin${FS}jar
|
||||||
|
JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner
|
||||||
|
JAVAC=$TESTJAVA${FS}bin${FS}javac
|
||||||
|
|
||||||
|
rm js.jks
|
||||||
|
|
||||||
|
echo class A1 {} > A1.java
|
||||||
|
echo class A2 {} > A2.java
|
||||||
|
echo class A3 {} > A3.java
|
||||||
|
echo class A4 {} > A4.java
|
||||||
|
echo class A5 {} > A5.java
|
||||||
|
echo class A6 {} > A6.java
|
||||||
|
|
||||||
|
$JAVAC A1.java A2.java A3.java A4.java A5.java A6.java
|
||||||
|
YEAR=`date +%Y`
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# First part: output format
|
||||||
|
# ==========================================================
|
||||||
|
|
||||||
|
$KT -genkeypair -alias a1 -dname CN=a1 -validity 365
|
||||||
|
$KT -genkeypair -alias a2 -dname CN=a2 -validity 365
|
||||||
|
|
||||||
|
# a.jar includes 8 unsigned, 2 signed by a1 and a2, 2 signed by a3
|
||||||
|
$JAR cvf a.jar A1.class A2.class
|
||||||
|
$JARSIGNER -keystore js.jks -storepass changeit a.jar a1
|
||||||
|
$JAR uvf a.jar A3.class A4.class
|
||||||
|
$JARSIGNER -keystore js.jks -storepass changeit a.jar a2
|
||||||
|
$JAR uvf a.jar A5.class A6.class
|
||||||
|
|
||||||
|
# Verify OK
|
||||||
|
$JARSIGNER -verify a.jar
|
||||||
|
[ $? = 0 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 4(chainNotValidated)+16(hasUnsignedEntry)+32(aliasNotInStore)
|
||||||
|
$JARSIGNER -verify a.jar -strict
|
||||||
|
[ $? = 52 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 16(hasUnsignedEntry)
|
||||||
|
$JARSIGNER -verify a.jar -strict -keystore js.jks
|
||||||
|
[ $? = 16 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 16(hasUnsignedEntry)+32(notSignedByAlias)
|
||||||
|
$JARSIGNER -verify a.jar a1 -strict -keystore js.jks
|
||||||
|
[ $? = 48 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 16(hasUnsignedEntry)
|
||||||
|
$JARSIGNER -verify a.jar a1 a2 -strict -keystore js.jks
|
||||||
|
[ $? = 16 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 12 entries all together
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose | grep $YEAR | wc -l`
|
||||||
|
[ $LINES = 12 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 12 entries all listed
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose:grouped | grep $YEAR | wc -l`
|
||||||
|
[ $LINES = 12 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 3 groups: unrelated, signed, unsigned
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose:summary | grep $YEAR | wc -l`
|
||||||
|
[ $LINES = 3 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 4 groups: unrelated, signed by a1/a2, signed by a2, unsigned
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep $YEAR | wc -l`
|
||||||
|
[ $LINES = 4 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 2*2 for A1/A2, 2 for A3/A4
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose -certs | grep "\[certificate" | wc -l`
|
||||||
|
[ $LINES = 6 ] || exit $LINENO
|
||||||
|
|
||||||
|
# a1,a2 for A1/A2, a2 for A3/A4
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose:grouped -certs | grep "\[certificate" | wc -l`
|
||||||
|
[ $LINES = 3 ] || exit $LINENO
|
||||||
|
|
||||||
|
# a1,a2 for A1/A2, a2 for A3/A4
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "\[certificate" | wc -l`
|
||||||
|
[ $LINES = 3 ] || exit $LINENO
|
||||||
|
|
||||||
|
# 4 groups
|
||||||
|
LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "more)" | wc -l`
|
||||||
|
[ $LINES = 4 ] || exit $LINENO
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# Second part: exit code 2, 4, 8
|
||||||
|
# 16 and 32 already covered in the first part
|
||||||
|
# ==========================================================
|
||||||
|
|
||||||
|
$KT -genkeypair -alias expiring -dname CN=expiring -startdate -1m
|
||||||
|
$KT -genkeypair -alias expired -dname CN=expired -startdate -10m
|
||||||
|
$KT -genkeypair -alias notyetvalid -dname CN=notyetvalid -startdate +1m
|
||||||
|
$KT -genkeypair -alias badku -dname CN=badku -ext KU=cRLSign -validity 365
|
||||||
|
$KT -genkeypair -alias badeku -dname CN=badeku -ext EKU=sa -validity 365
|
||||||
|
$KT -genkeypair -alias goodku -dname CN=goodku -ext KU=dig -validity 365
|
||||||
|
$KT -genkeypair -alias goodeku -dname CN=goodeku -ext EKU=codesign -validity 365
|
||||||
|
|
||||||
|
# badchain signed by ca, but ca is removed later
|
||||||
|
$KT -genkeypair -alias badchain -dname CN=badchain -validity 365
|
||||||
|
$KT -genkeypair -alias ca -dname CN=ca -ext bc -validity 365
|
||||||
|
$KT -certreq -alias badchain | $KT -gencert -alias ca -validity 365 | \
|
||||||
|
$KT -importcert -alias badchain
|
||||||
|
$KT -delete -alias ca
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expiring
|
||||||
|
[ $? = 2 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expired
|
||||||
|
[ $? = 4 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar notyetvalid
|
||||||
|
[ $? = 4 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badku
|
||||||
|
[ $? = 8 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badeku
|
||||||
|
[ $? = 8 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar goodku
|
||||||
|
[ $? = 0 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar goodeku
|
||||||
|
[ $? = 0 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badchain
|
||||||
|
[ $? = 4 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -verify a.jar
|
||||||
|
[ $? = 0 ] || exit $LINENO
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# Third part: -certchain test
|
||||||
|
# ==========================================================
|
||||||
|
|
||||||
|
# altchain signed by ca2, but ca2 is removed later
|
||||||
|
$KT -genkeypair -alias altchain -dname CN=altchain -validity 365
|
||||||
|
$KT -genkeypair -alias ca2 -dname CN=ca2 -ext bc -validity 365
|
||||||
|
$KT -certreq -alias altchain | $KT -gencert -alias ca2 -validity 365 -rfc > certchain
|
||||||
|
$KT -exportcert -alias ca2 -rfc >> certchain
|
||||||
|
$KT -delete -alias ca2
|
||||||
|
|
||||||
|
# Now altchain is still self-signed
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar altchain
|
||||||
|
[ $? = 0 ] || exit $LINENO
|
||||||
|
|
||||||
|
# If -certchain is used, then it's bad
|
||||||
|
$JARSIGNER -strict -keystore js.jks -storepass changeit -certchain certchain a.jar altchain
|
||||||
|
[ $? = 4 ] || exit $LINENO
|
||||||
|
|
||||||
|
$JARSIGNER -verify a.jar
|
||||||
|
[ $? = 0 ] || exit $LINENO
|
||||||
|
|
||||||
|
echo OK
|
||||||
|
exit 0
|
Loading…
x
Reference in New Issue
Block a user