提交 b05e2d58 编写于 作者: C coffeys

Merge

/* /*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2014, Oracle and/or its affiliates. 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
...@@ -34,6 +34,9 @@ import sun.security.util.Debug; ...@@ -34,6 +34,9 @@ import sun.security.util.Debug;
import sun.security.pkcs11.wrapper.*; import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Session manager. There is one session manager object per PKCS#11 * Session manager. There is one session manager object per PKCS#11
* provider. It allows code to checkout a session, release it * provider. It allows code to checkout a session, release it
...@@ -77,7 +80,7 @@ final class SessionManager { ...@@ -77,7 +80,7 @@ final class SessionManager {
private final int maxSessions; private final int maxSessions;
// total number of active sessions // total number of active sessions
private int activeSessions; private AtomicInteger activeSessions = new AtomicInteger();
// pool of available object sessions // pool of available object sessions
private final Pool objSessions; private final Pool objSessions;
...@@ -118,7 +121,7 @@ final class SessionManager { ...@@ -118,7 +121,7 @@ final class SessionManager {
return (maxSessions <= DEFAULT_MAX_SESSIONS); return (maxSessions <= DEFAULT_MAX_SESSIONS);
} }
synchronized Session getObjSession() throws PKCS11Exception { Session getObjSession() throws PKCS11Exception {
Session session = objSessions.poll(); Session session = objSessions.poll();
if (session != null) { if (session != null) {
return ensureValid(session); return ensureValid(session);
...@@ -131,7 +134,7 @@ final class SessionManager { ...@@ -131,7 +134,7 @@ final class SessionManager {
return ensureValid(session); return ensureValid(session);
} }
synchronized Session getOpSession() throws PKCS11Exception { Session getOpSession() throws PKCS11Exception {
Session session = opSessions.poll(); Session session = opSessions.poll();
if (session != null) { if (session != null) {
return ensureValid(session); return ensureValid(session);
...@@ -139,7 +142,7 @@ final class SessionManager { ...@@ -139,7 +142,7 @@ final class SessionManager {
// create a new session rather than re-using an obj session // create a new session rather than re-using an obj session
// that avoids potential expensive cancels() for Signatures & RSACipher // that avoids potential expensive cancels() for Signatures & RSACipher
if (maxSessions == Integer.MAX_VALUE || if (maxSessions == Integer.MAX_VALUE ||
activeSessions < maxSessions) { activeSessions.get() < maxSessions) {
session = openSession(); session = openSession();
return ensureValid(session); return ensureValid(session);
} }
...@@ -155,20 +158,20 @@ final class SessionManager { ...@@ -155,20 +158,20 @@ final class SessionManager {
return session; return session;
} }
synchronized Session killSession(Session session) { Session killSession(Session session) {
if ((session == null) || (token.isValid() == false)) { if ((session == null) || (token.isValid() == false)) {
return null; return null;
} }
if (debug != null) { if (debug != null) {
String location = new Exception().getStackTrace()[2].toString(); String location = new Exception().getStackTrace()[2].toString();
System.out.println("Killing session (" + location + ") active: " System.out.println("Killing session (" + location + ") active: "
+ activeSessions); + activeSessions.get());
} }
closeSession(session); closeSession(session);
return null; return null;
} }
synchronized Session releaseSession(Session session) { Session releaseSession(Session session) {
if ((session == null) || (token.isValid() == false)) { if ((session == null) || (token.isValid() == false)) {
return null; return null;
} }
...@@ -181,13 +184,13 @@ final class SessionManager { ...@@ -181,13 +184,13 @@ final class SessionManager {
return null; return null;
} }
synchronized void demoteObjSession(Session session) { void demoteObjSession(Session session) {
if (token.isValid() == false) { if (token.isValid() == false) {
return; return;
} }
if (debug != null) { if (debug != null) {
System.out.println("Demoting session, active: " + System.out.println("Demoting session, active: " +
activeSessions); activeSessions.get());
} }
boolean present = objSessions.remove(session); boolean present = objSessions.remove(session);
if (present == false) { if (present == false) {
...@@ -200,38 +203,41 @@ final class SessionManager { ...@@ -200,38 +203,41 @@ final class SessionManager {
private Session openSession() throws PKCS11Exception { private Session openSession() throws PKCS11Exception {
if ((maxSessions != Integer.MAX_VALUE) && if ((maxSessions != Integer.MAX_VALUE) &&
(activeSessions >= maxSessions)) { (activeSessions.get() >= maxSessions)) {
throw new ProviderException("No more sessions available"); throw new ProviderException("No more sessions available");
} }
long id = token.p11.C_OpenSession long id = token.p11.C_OpenSession
(token.provider.slotID, openSessionFlags, null, null); (token.provider.slotID, openSessionFlags, null, null);
Session session = new Session(token, id); Session session = new Session(token, id);
activeSessions++; activeSessions.incrementAndGet();
if (debug != null) { if (debug != null) {
if (activeSessions > maxActiveSessions) { synchronized(this) {
maxActiveSessions = activeSessions; if (activeSessions.get() > maxActiveSessions) {
maxActiveSessions = activeSessions.get();
if (maxActiveSessions % 10 == 0) { if (maxActiveSessions % 10 == 0) {
System.out.println("Open sessions: " + maxActiveSessions); System.out.println("Open sessions: " + maxActiveSessions);
} }
} }
} }
}
return session; return session;
} }
private void closeSession(Session session) { private void closeSession(Session session) {
session.close(); session.close();
activeSessions--; activeSessions.decrementAndGet();
} }
private static final class Pool { public static final class Pool {
private final SessionManager mgr; private final SessionManager mgr;
private final List<Session> pool; private final ConcurrentLinkedDeque<Session> pool;
Pool(SessionManager mgr) { Pool(SessionManager mgr) {
this.mgr = mgr; this.mgr = mgr;
pool = new ArrayList<Session>(); pool = new ConcurrentLinkedDeque<Session>();
} }
boolean remove(Session session) { boolean remove(Session session) {
...@@ -239,45 +245,40 @@ final class SessionManager { ...@@ -239,45 +245,40 @@ final class SessionManager {
} }
Session poll() { Session poll() {
int n = pool.size(); return pool.pollLast();
if (n == 0) {
return null;
}
Session session = pool.remove(n - 1);
return session;
} }
void release(Session session) { void release(Session session) {
pool.add(session); pool.offer(session);
// if there are idle sessions, close them
if (session.hasObjects()) { if (session.hasObjects()) {
return; return;
} }
int n = pool.size(); int n = pool.size();
if (n < 5) { if (n < 5) {
return; return;
} }
Session oldestSession = pool.get(0);
Session oldestSession;
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if (session.isLive(time) && oldestSession.isLive(time)) {
return;
}
Collections.sort(pool);
int i = 0; int i = 0;
while (i < n - 1) { // always keep at least 1 session open // Check if the session head is too old and continue through queue
oldestSession = pool.get(i); // until only one is left.
if (oldestSession.isLive(time)) { do {
oldestSession = pool.peek();
if (oldestSession == null || oldestSession.isLive(time) ||
!pool.remove(oldestSession)) {
break; break;
} }
i++; i++;
mgr.closeSession(oldestSession); mgr.closeSession(oldestSession);
} } while ((n - i) > 1);
if (debug != null) { if (debug != null) {
System.out.println("Closing " + i + " idle sessions, active: " System.out.println("Closing " + i + " idle sessions, active: "
+ mgr.activeSessions); + mgr.activeSessions);
} }
List<Session> subList = pool.subList(0, i);
subList.clear();
} }
} }
......
...@@ -58,6 +58,7 @@ import java.util.logging.Logger; ...@@ -58,6 +58,7 @@ import java.util.logging.Logger;
*/ */
public class TestLoggerBundleSync { public class TestLoggerBundleSync {
static final boolean VERBOSE = false;
static volatile Exception thrown = null; static volatile Exception thrown = null;
static volatile boolean goOn = true; static volatile boolean goOn = true;
...@@ -65,6 +66,7 @@ public class TestLoggerBundleSync { ...@@ -65,6 +66,7 @@ public class TestLoggerBundleSync {
static final long TIME = 4 * 1000; // 4 sec. static final long TIME = 4 * 1000; // 4 sec.
static final long STEP = 1 * 1000; // message every 1 sec. static final long STEP = 1 * 1000; // message every 1 sec.
static final int LCOUNT = 50; // change bundle 50 times... static final int LCOUNT = 50; // change bundle 50 times...
static final AtomicLong ignoreLogCount = new AtomicLong(0);
static final AtomicLong setRBcount = new AtomicLong(0); static final AtomicLong setRBcount = new AtomicLong(0);
static final AtomicLong setRBNameCount = new AtomicLong(0); static final AtomicLong setRBNameCount = new AtomicLong(0);
static final AtomicLong getRBcount = new AtomicLong(0); static final AtomicLong getRBcount = new AtomicLong(0);
...@@ -150,6 +152,7 @@ public class TestLoggerBundleSync { ...@@ -150,6 +152,7 @@ public class TestLoggerBundleSync {
long sSetRBNameCount = setRBNameCount.get(); long sSetRBNameCount = setRBNameCount.get();
long sCheckCount = checkCount.get(); long sCheckCount = checkCount.get();
long sNextLong = nextLong.get(); long sNextLong = nextLong.get();
long sIgnoreLogCount = ignoreLogCount.get();
List<Thread> threads = new ArrayList<>(); List<Thread> threads = new ArrayList<>();
for (Class<? extends ResourceBundle> type : classes) { for (Class<? extends ResourceBundle> type : classes) {
threads.add(new SetRB(type)); threads.add(new SetRB(type));
...@@ -181,21 +184,58 @@ public class TestLoggerBundleSync { ...@@ -181,21 +184,58 @@ public class TestLoggerBundleSync {
+ " resource bundles set by " + classes.size() + " Thread(s),"); + " resource bundles set by " + classes.size() + " Thread(s),");
System.out.println("\t " + (setRBNameCount.get() - sSetRBNameCount) System.out.println("\t " + (setRBNameCount.get() - sSetRBNameCount)
+ " resource bundle names set by " + classes.size() + " Thread(s),"); + " resource bundle names set by " + classes.size() + " Thread(s),");
System.out.println("\t " + (ignoreLogCount.get() - sIgnoreLogCount)
+ " log messages emitted by other GetRB threads were ignored"
+ " to ensure MT test consistency,");
System.out.println("\t ThreadMXBean.findDeadlockedThreads called " System.out.println("\t ThreadMXBean.findDeadlockedThreads called "
+ (checkCount.get() -sCheckCount) + " times by 1 Thread."); + (checkCount.get() -sCheckCount) + " times by 1 Thread.");
} }
final static class GetRB extends Thread { final static class GetRB extends Thread {
final static class MyHandler extends Handler { final class MyHandler extends Handler {
volatile ResourceBundle rb; volatile ResourceBundle rb;
volatile String rbName; volatile String rbName;
volatile int count = 0; volatile int count = 0;
@Override @Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
Object[] params = record.getParameters();
// Each GetRB thread has its own handler, but since they
// log into the same logger, each handler may receive
// messages emitted by other threads.
// This means that GetRB#2.handler may receive a message
// emitted by GetRB#1 at a time where the resource bundle
// was still null.
// To avoid falling into this trap, the GetRB thread passes
// 'this' as argument to the messages it logs - which does
// allow us here to ignore messages that where not emitted
// by our own GetRB.this thread...
if (params.length == 1) {
if (params[0] == GetRB.this) {
// The message was emitted by our thread.
count++; count++;
rb = record.getResourceBundle(); rb = record.getResourceBundle();
rbName = record.getResourceBundleName(); rbName = record.getResourceBundleName();
} else {
// The message was emitted by another thread: just
// ignore it, as it may have been emitted at a time
// where the resource bundle was still null, and
// processing it may overwrite the 'rb' and 'rbName'
// recorded from the message emitted by our own thread.
if (VERBOSE) {
System.out.println("Ignoring message logged by " + params[0]);
}
ignoreLogCount.incrementAndGet();
}
} else {
ignoreLogCount.incrementAndGet();
System.err.println("Unexpected message received");
}
}
void reset() {
rbName = null;
rb = null;
} }
@Override @Override
...@@ -207,6 +247,7 @@ public class TestLoggerBundleSync { ...@@ -207,6 +247,7 @@ public class TestLoggerBundleSync {
} }
}; };
final MyHandler handler = new MyHandler(); final MyHandler handler = new MyHandler();
@Override @Override
public void run() { public void run() {
try { try {
...@@ -234,9 +275,10 @@ public class TestLoggerBundleSync { ...@@ -234,9 +275,10 @@ public class TestLoggerBundleSync {
+ handler.getLevel()); + handler.getLevel());
} }
final int countBefore = handler.count; final int countBefore = handler.count;
handler.reset();
ll.setLevel(Level.FINEST); ll.setLevel(Level.FINEST);
ll.addHandler(handler); ll.addHandler(handler);
ll.fine("dummy"); ll.log(Level.FINE, "dummy {0}", this);
ll.removeHandler(handler); ll.removeHandler(handler);
final int countAfter = handler.count; final int countAfter = handler.count;
if (countBefore == countAfter) { if (countBefore == countAfter) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册