1 #![cfg(feature = "invocation")]
2
3 use std::{
4 sync::{Arc, Barrier},
5 thread::spawn,
6 };
7
8 use jni::{
9 objects::{AutoLocal, JValue},
10 sys::jint,
11 JNIEnv,
12 };
13
14 mod util;
15 use util::{attach_current_thread, unwrap};
16
17 #[test]
weak_ref_works_in_other_threads()18 pub fn weak_ref_works_in_other_threads() {
19 const ITERS_PER_THREAD: usize = 10_000;
20
21 let mut env = attach_current_thread();
22 let mut join_handlers = Vec::new();
23
24 let atomic_integer_local = AutoLocal::new(
25 unwrap(
26 env.new_object(
27 "java/util/concurrent/atomic/AtomicInteger",
28 "(I)V",
29 &[JValue::from(0)],
30 ),
31 &env,
32 ),
33 &env,
34 );
35 let atomic_integer =
36 unwrap(env.new_weak_ref(&atomic_integer_local), &env).expect("weak ref should not be null");
37
38 // Test with a different number of threads (from 2 to 8)
39 for thread_num in 2..9 {
40 let barrier = Arc::new(Barrier::new(thread_num));
41
42 for _ in 0..thread_num {
43 let barrier = barrier.clone();
44 let atomic_integer = atomic_integer.clone();
45
46 let jh = spawn(move || {
47 let mut env = attach_current_thread();
48 barrier.wait();
49 for _ in 0..ITERS_PER_THREAD {
50 let atomic_integer = env.auto_local(
51 unwrap(atomic_integer.upgrade_local(&env), &env)
52 .expect("AtomicInteger shouldn't have been GC'd yet"),
53 );
54 unwrap(
55 unwrap(
56 env.call_method(&atomic_integer, "incrementAndGet", "()I", &[]),
57 &env,
58 )
59 .i(),
60 &env,
61 );
62 }
63 });
64 join_handlers.push(jh);
65 }
66
67 for jh in join_handlers.drain(..) {
68 jh.join().unwrap();
69 }
70
71 let expected = (ITERS_PER_THREAD * thread_num) as jint;
72 assert_eq!(
73 expected,
74 unwrap(
75 unwrap(
76 env.call_method(
77 &atomic_integer_local,
78 "getAndSet",
79 "(I)I",
80 &[JValue::from(0)]
81 ),
82 &env,
83 )
84 .i(),
85 &env,
86 )
87 );
88 }
89 }
90
91 #[test]
weak_ref_is_actually_weak()92 fn weak_ref_is_actually_weak() {
93 let mut env = attach_current_thread();
94
95 // This test uses `with_local_frame` to work around issue #109.
96
97 fn run_gc(env: &mut JNIEnv) {
98 unwrap(
99 env.with_local_frame(1, |env| {
100 env.call_static_method("java/lang/System", "gc", "()V", &[])?;
101 Ok(())
102 }),
103 env,
104 );
105 }
106
107 for _ in 0..100 {
108 let obj_local = unwrap(
109 env.with_local_frame_returning_local(2, |env| {
110 env.new_object("java/lang/Object", "()V", &[])
111 }),
112 &env,
113 );
114 let obj_local = env.auto_local(obj_local);
115
116 let obj_weak =
117 unwrap(env.new_weak_ref(&obj_local), &env).expect("weak ref should not be null");
118
119 let obj_weak2 =
120 unwrap(obj_weak.clone_in_jvm(&env), &env).expect("weak ref should not be null");
121
122 run_gc(&mut env);
123
124 for obj_weak in &[&obj_weak, &obj_weak2] {
125 {
126 let obj_local_from_weak = env.auto_local(
127 unwrap(obj_weak.upgrade_local(&env), &env)
128 .expect("object shouldn't have been GC'd yet"),
129 );
130
131 assert!(!obj_local_from_weak.is_null());
132 assert!(unwrap(
133 env.is_same_object(&obj_local_from_weak, &obj_local),
134 &env,
135 ));
136 }
137
138 {
139 let obj_global_from_weak = unwrap(obj_weak.upgrade_global(&env), &env)
140 .expect("object shouldn't have been GC'd yet");
141
142 assert!(!obj_global_from_weak.is_null());
143 assert!(unwrap(
144 env.is_same_object(&obj_global_from_weak, &obj_local),
145 &env,
146 ));
147 }
148
149 assert!(unwrap(obj_weak.is_same_object(&env, &obj_local), &env));
150
151 assert!(
152 !unwrap(obj_weak.is_garbage_collected(&env), &env),
153 "`is_garbage_collected` returned incorrect value"
154 );
155 }
156
157 assert!(unwrap(
158 obj_weak.is_weak_ref_to_same_object(&env, &obj_weak2),
159 &env,
160 ));
161
162 drop(obj_local);
163 run_gc(&mut env);
164
165 for obj_weak in &[&obj_weak, &obj_weak2] {
166 {
167 let obj_local_from_weak = unwrap(obj_weak.upgrade_local(&env), &env);
168
169 assert!(
170 obj_local_from_weak.is_none(),
171 "object should have been GC'd"
172 );
173 }
174
175 {
176 let obj_global_from_weak = unwrap(obj_weak.upgrade_global(&env), &env);
177
178 assert!(
179 obj_global_from_weak.is_none(),
180 "object should have been GC'd"
181 );
182 }
183
184 assert!(
185 unwrap(obj_weak.is_garbage_collected(&env), &env),
186 "`is_garbage_collected` returned incorrect value"
187 );
188 }
189
190 assert!(unwrap(
191 obj_weak.is_weak_ref_to_same_object(&env, &obj_weak2),
192 &env,
193 ));
194 }
195 }
196