1 | /* |
2 | * $Id: NativeResourceRef.java,v 1.2 2004/08/19 02:15:25 hastings Exp $ |
3 | * |
4 | * (c) Copyright, Moebius Solutions, Inc., 2004 |
5 | * |
6 | * All Rights Reserved |
7 | * |
8 | * This material may be reproduced by or for the U. S. Government |
9 | * pursuant to the copyright license under the clause at |
10 | * DFARS 252.227-7014 (OCT 2001). |
11 | */ |
12 | |
13 | package com.moesol.bindings.platform_sdk.windows_api; |
14 | |
15 | import java.lang.ref.PhantomReference; |
16 | import java.lang.ref.ReferenceQueue; |
17 | import java.util.Collections; |
18 | import java.util.HashMap; |
19 | import java.util.Map; |
20 | import java.util.logging.Level; |
21 | import java.util.logging.Logger; |
22 | |
23 | import com.moesol.bindings.AllocationLocation; |
24 | import com.moesol.bindings.NativeLeakDetectionThread; |
25 | import com.moesol.bindings.NativeResourceChecker; |
26 | |
27 | |
28 | /** |
29 | * Check for native handle leaks. A handle is any |
30 | * java object which holds a native pointer. |
31 | * |
32 | * @author robert |
33 | */ |
34 | public class NativeResourceRef extends PhantomReference |
35 | implements NativeResourceChecker |
36 | { |
37 | /** call from assert always returns true */ |
38 | public static boolean recordCreateLocation(Object holder, long native_handle) { |
39 | if (native_handle == 0) { |
40 | return true; |
41 | } |
42 | g_owned_handles.put(new Long(native_handle), new NativeResourceRef(holder, |
43 | NativeLeakDetectionThread.instance().getQ())); |
44 | return true; |
45 | } |
46 | |
47 | /** call from assert always returns true */ |
48 | public static boolean removeCreateLocation(long native_handle) { |
49 | if (native_handle == 0) { |
50 | return true; |
51 | } |
52 | NativeResourceRef c = (NativeResourceRef) g_owned_handles.remove(new Long( |
53 | native_handle)); |
54 | if (c != null) { |
55 | c.release(); |
56 | } |
57 | return true; |
58 | } |
59 | |
60 | private NativeResourceRef(Object h, ReferenceQueue q) { |
61 | super(h, q); |
62 | } |
63 | public void check() { |
64 | assert(isReleased() || reportLeak()); |
65 | } |
66 | private void release() { |
67 | clear(); |
68 | m_create_location = null; |
69 | } |
70 | private boolean isReleased() { |
71 | return m_create_location == null; |
72 | } |
73 | private boolean reportLeak() { |
74 | logger.log(Level.WARNING, "m_handle leaked " + this, |
75 | m_create_location); |
76 | incLeakCount(); |
77 | return true; |
78 | } |
79 | |
80 | public synchronized static long getLeakCount() { |
81 | return g_leak_count; |
82 | } |
83 | private synchronized static void incLeakCount() { |
84 | g_leak_count++; |
85 | } |
86 | |
87 | private static Logger logger = Logger.getLogger(NativeResourceRef.class.getName()); |
88 | private static long g_leak_count = 0; |
89 | |
90 | private AllocationLocation m_create_location = new AllocationLocation(); |
91 | private static Map g_owned_handles = Collections.synchronizedMap(new HashMap()); |
92 | } |