View | Details | Raw Unified | Return to bug 52850
Collapse All | Expand All

(-)java/org/apache/catalina/loader/WebappClassLoader.java (-35 / +71 lines)
Lines 2177-2184 Link Here
2177
                    }
2177
                    }
2178
2178
2179
                    // TimerThread can be stopped safely so treat separately
2179
                    // TimerThread can be stopped safely so treat separately
2180
                    if (thread.getClass().getName().equals(
2180
                    // "java.util.TimerThread" in Sun/Oracle JDK
2181
                            "java.util.TimerThread") &&
2181
                    // "java.util.Timer$TimerImpl" in Apache Harmony and in IBM JDK
2182
                    if (thread.getClass().getName().startsWith("java.util.Timer") &&
2182
                            clearReferencesStopTimerThreads) {
2183
                            clearReferencesStopTimerThreads) {
2183
                        clearReferencesStopTimerThread(thread);
2184
                        clearReferencesStopTimerThread(thread);
2184
                        continue;
2185
                        continue;
Lines 2201-2213 Link Here
2201
                    // If the thread has been started via an executor, try
2202
                    // If the thread has been started via an executor, try
2202
                    // shutting down the executor
2203
                    // shutting down the executor
2203
                    try {
2204
                    try {
2204
                        Field targetField =
2205
                        // Runnable wrapped by Thread
2205
                            thread.getClass().getDeclaredField("target");
2206
                        // "target" in Sun/Oracle JDK
2206
                        targetField.setAccessible(true);
2207
                        // "runnable" in IBM JDK
2207
                        Object target = targetField.get(thread);
2208
                        // "action" in Apache Harmony
2208
                        
2209
                        Object target = null;
2210
                        for (String fieldName : new String[] { "target",
2211
                                "runnable", "action" }) {
2212
                            try {
2213
                                Field targetField = thread.getClass()
2214
                                        .getDeclaredField(fieldName);
2215
                                targetField.setAccessible(true);
2216
                                target = targetField.get(thread);
2217
                                break;
2218
                            } catch (NoSuchFieldException nfe) {
2219
                                continue;
2220
                            }
2221
                        }
2222
2223
                        // "java.util.concurrent" code is in public domain,
2224
                        // so all implementations are similar
2209
                        if (target != null &&
2225
                        if (target != null &&
2210
                                target.getClass().getCanonicalName().equals(
2226
                                target.getClass().getCanonicalName() != null
2227
                                && target.getClass().getCanonicalName().equals(
2211
                                "java.util.concurrent.ThreadPoolExecutor.Worker")) {
2228
                                "java.util.concurrent.ThreadPoolExecutor.Worker")) {
2212
                            Field executorField =
2229
                            Field executorField =
2213
                                target.getClass().getDeclaredField("this$0");
2230
                                target.getClass().getDeclaredField("this$0");
Lines 2276-2312 Link Here
2276
    
2293
    
2277
    
2294
    
2278
    private void clearReferencesStopTimerThread(Thread thread) {
2295
    private void clearReferencesStopTimerThread(Thread thread) {
2279
        
2296
2280
        // Need to get references to:
2297
        // Need to get references to:
2281
        // - newTasksMayBeScheduled field
2298
        // in Sun/Oracle JDK:
2299
        // - newTasksMayBeScheduled field (in java.util.TimerThread)
2282
        // - queue field
2300
        // - queue field
2283
        // - queue.clear()
2301
        // - queue.clear()
2302
        // in IBM JDK, Apache Harmony:
2303
        // - cancel() method (in java.util.Timer$TimerImpl)
2304
2305
        try {
2306
2307
            try {
2308
                Field newTasksMayBeScheduledField =
2309
                    thread.getClass().getDeclaredField("newTasksMayBeScheduled");
2310
                newTasksMayBeScheduledField.setAccessible(true);
2311
                Field queueField = thread.getClass().getDeclaredField("queue");
2312
                queueField.setAccessible(true);
2284
        
2313
        
2285
        try {
2314
                Object queue = queueField.get(thread);
2286
            Field newTasksMayBeScheduledField =
2315
                
2287
                thread.getClass().getDeclaredField("newTasksMayBeScheduled");
2316
                Method clearMethod = queue.getClass().getDeclaredMethod("clear");
2288
            newTasksMayBeScheduledField.setAccessible(true);
2317
                clearMethod.setAccessible(true);
2289
            Field queueField = thread.getClass().getDeclaredField("queue");
2318
                
2290
            queueField.setAccessible(true);
2319
                synchronized(queue) {
2291
    
2320
                    newTasksMayBeScheduledField.setBoolean(thread, false);
2292
            Object queue = queueField.get(thread);
2321
                    clearMethod.invoke(queue);
2293
            
2322
                    queue.notify();  // In case queue was already empty.
2294
            Method clearMethod = queue.getClass().getDeclaredMethod("clear");
2323
                }
2295
            clearMethod.setAccessible(true);
2324
2296
            
2325
            }catch (NoSuchFieldException nfe){
2297
            synchronized(queue) {
2326
                Method cancelMethod = thread.getClass().getDeclaredMethod("cancel");
2298
                newTasksMayBeScheduledField.setBoolean(thread, false);
2327
                synchronized(thread) {
2299
                clearMethod.invoke(queue);
2328
                    cancelMethod.setAccessible(true);
2300
                queue.notify();  // In case queue was already empty.
2329
                    cancelMethod.invoke(thread);
2330
                }
2301
            }
2331
            }
2302
            
2332
2303
            log.error(sm.getString("webappClassLoader.warnTimerThread",
2333
            log.error(sm.getString("webappClassLoader.warnTimerThread",
2304
                    contextName, thread.getName()));
2334
                    contextName, thread.getName()));
2305
2335
2306
        } catch (NoSuchFieldException e) {
2307
            log.warn(sm.getString(
2308
                    "webappClassLoader.stopTimerThreadFail",
2309
                    thread.getName(), contextName), e);
2310
        } catch (IllegalAccessException e) {
2336
        } catch (IllegalAccessException e) {
2311
            log.warn(sm.getString(
2337
            log.warn(sm.getString(
2312
                    "webappClassLoader.stopTimerThreadFail",
2338
                    "webappClassLoader.stopTimerThreadFail",
Lines 2340-2356 Link Here
2340
                Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
2366
                Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
2341
            Field tableField = tlmClass.getDeclaredField("table");
2367
            Field tableField = tlmClass.getDeclaredField("table");
2342
            tableField.setAccessible(true);
2368
            tableField.setAccessible(true);
2343
            
2369
            Method expungeStaleEntriesMethod = tlmClass.getDeclaredMethod("expungeStaleEntries");
2370
            expungeStaleEntriesMethod.setAccessible(true);
2371
2344
            for (int i = 0; i < threads.length; i++) {
2372
            for (int i = 0; i < threads.length; i++) {
2345
                Object threadLocalMap;
2373
                Object threadLocalMap;
2346
                if (threads[i] != null) {
2374
                if (threads[i] != null) {
2375
2347
                    // Clear the first map
2376
                    // Clear the first map
2348
                    threadLocalMap = threadLocalsField.get(threads[i]);
2377
                    threadLocalMap = threadLocalsField.get(threads[i]);
2349
                    clearThreadLocalMap(threadLocalMap, tableField);
2378
                    if (null != threadLocalMap){
2379
                        expungeStaleEntriesMethod.invoke(threadLocalMap);
2380
                        checkThreadLocalMapForLeaks(threadLocalMap, tableField);
2381
                    }
2382
2350
                    // Clear the second map
2383
                    // Clear the second map
2351
                    threadLocalMap =
2384
                    threadLocalMap =
2352
                        inheritableThreadLocalsField.get(threads[i]);
2385
                        inheritableThreadLocalsField.get(threads[i]);
2353
                    clearThreadLocalMap(threadLocalMap, tableField);
2386
                    if (null != threadLocalMap){
2387
                        expungeStaleEntriesMethod.invoke(threadLocalMap);
2388
                        checkThreadLocalMapForLeaks(threadLocalMap, tableField);
2389
                    }
2354
                }
2390
                }
2355
            }
2391
            }
2356
        } catch (SecurityException e) {
2392
        } catch (SecurityException e) {
Lines 2383-2389 Link Here
2383
     * points to the internal table to save re-calculating it on every
2419
     * points to the internal table to save re-calculating it on every
2384
     * call to this method.
2420
     * call to this method.
2385
     */
2421
     */
2386
    private void clearThreadLocalMap(Object map, Field internalTableField)
2422
    private void checkThreadLocalMapForLeaks(Object map, Field internalTableField)
2387
            throws NoSuchMethodException, IllegalAccessException,
2423
            throws NoSuchMethodException, IllegalAccessException,
2388
            NoSuchFieldException, InvocationTargetException {
2424
            NoSuchFieldException, InvocationTargetException {
2389
        if (map != null) {
2425
        if (map != null) {

Return to bug 52850