|
12 | 12 | // See the License for the specific language governing permissions and
|
13 | 13 | // limitations under the License.
|
14 | 14 |
|
15 |
| -use std::{fs, mem}; |
| 15 | +use std::{fs, mem, thread, time}; |
16 | 16 | use std::any::Any;
|
17 | 17 | use std::convert::TryFrom;
|
18 | 18 | use std::env;
|
@@ -1013,6 +1013,44 @@ impl Jvm {
|
1013 | 1013 | }
|
1014 | 1014 | }
|
1015 | 1015 | }
|
| 1016 | + |
| 1017 | + /// Returns the first `Instance` that is available from the passed `InstanceReceiver`s, |
| 1018 | + /// along with the index of the receiver that was selected and actually returned the instance. |
| 1019 | + /// |
| 1020 | + /// This is a mostly naive implementation of select, because of [absence for selecting among mpsc channels](https://github.com/rust-lang/rust/issues/27800). |
| 1021 | + pub fn select(instance_receivers: &[&InstanceReceiver]) -> errors::Result<(usize, Instance)> { |
| 1022 | + loop { |
| 1023 | + for (index, ir) in instance_receivers.iter().enumerate() { |
| 1024 | + let res = ir.rx.try_recv(); |
| 1025 | + if res.is_ok() { |
| 1026 | + return Ok((index, res.unwrap())); |
| 1027 | + } |
| 1028 | + } |
| 1029 | + thread::yield_now(); |
| 1030 | + } |
| 1031 | + } |
| 1032 | + |
| 1033 | + /// Returns the first `Instance` that is available from the passed `InstanceReceiver`s, |
| 1034 | + /// along with the index of the receiver that was selected and actually returned the instance. |
| 1035 | + /// |
| 1036 | + /// If there are no instances returned for the duration defined in timeout argument, an error is returned. |
| 1037 | + /// |
| 1038 | + /// This is a mostly naive implementation of select, because of [absence for selecting among mpsc channels](https://github.com/rust-lang/rust/issues/27800). |
| 1039 | + pub fn select_timeout(instance_receivers: &[&InstanceReceiver], timeout: &time::Duration) -> errors::Result<(usize, Instance)> { |
| 1040 | + let start = time::Instant::now(); |
| 1041 | + loop { |
| 1042 | + for (index, ir) in instance_receivers.iter().enumerate() { |
| 1043 | + let res = ir.rx.try_recv(); |
| 1044 | + if res.is_ok() { |
| 1045 | + return Ok((index, res.unwrap())); |
| 1046 | + } |
| 1047 | + } |
| 1048 | + if &start.elapsed() > timeout { |
| 1049 | + return Err(errors::J4RsError::Timeout); |
| 1050 | + } |
| 1051 | + thread::yield_now(); |
| 1052 | + } |
| 1053 | + } |
1016 | 1054 | }
|
1017 | 1055 |
|
1018 | 1056 | impl Drop for Jvm {
|
@@ -1739,11 +1777,13 @@ impl InstanceReceiver {
|
1739 | 1777 |
|
1740 | 1778 | impl Drop for InstanceReceiver {
|
1741 | 1779 | fn drop(&mut self) {
|
1742 |
| - debug("Dropping an InstanceReceiver"); |
1743 |
| - let p = self.tx_address as *mut Sender<Instance>; |
1744 |
| - unsafe { |
1745 |
| - let tx = Box::from_raw(p); |
1746 |
| - mem::drop(tx); |
| 1780 | + if self.tx_address > 0 { |
| 1781 | + debug("Dropping an InstanceReceiver"); |
| 1782 | + let p = self.tx_address as *mut Sender<Instance>; |
| 1783 | + unsafe { |
| 1784 | + let tx = Box::from_raw(p); |
| 1785 | + mem::drop(tx); |
| 1786 | + } |
1747 | 1787 | }
|
1748 | 1788 | }
|
1749 | 1789 | }
|
@@ -1867,7 +1907,7 @@ impl<'a> ChainableInstance<'a> {
|
1867 | 1907 |
|
1868 | 1908 | fn new_with_instance_ref(instance: &Instance, jvm: &'a Jvm) -> errors::Result<ChainableInstance<'a>> {
|
1869 | 1909 | let cloned = jvm.clone_instance(&instance)?;
|
1870 |
| - Ok(ChainableInstance { instance: cloned, jvm }) |
| 1910 | + Ok(ChainableInstance { instance: cloned, jvm }) |
1871 | 1911 | }
|
1872 | 1912 |
|
1873 | 1913 | pub fn collect(self) -> Instance {
|
@@ -2020,6 +2060,56 @@ mod api_unit_tests {
|
2020 | 2060 | let _ = fs_extra::remove_items(&vec![newdir]);
|
2021 | 2061 | }
|
2022 | 2062 |
|
| 2063 | + #[test] |
| 2064 | + fn test_select() { |
| 2065 | + let (tx1, rx1) = channel(); |
| 2066 | + let ir1 = InstanceReceiver::new(rx1, 0); |
| 2067 | + let (_tx2, rx2) = channel(); |
| 2068 | + let ir2 = InstanceReceiver::new(rx2, 0); |
| 2069 | + let (tx3, rx3) = channel(); |
| 2070 | + let ir3 = InstanceReceiver::new(rx3, 0); |
| 2071 | + |
| 2072 | + thread::spawn(move || { |
| 2073 | + let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap()); |
| 2074 | + // Block the thread as sending does not block the current thread |
| 2075 | + thread::sleep(time::Duration::from_millis(10)); |
| 2076 | + let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap()); |
| 2077 | + thread::sleep(time::Duration::from_millis(10)); |
| 2078 | + let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap()); |
| 2079 | + }); |
| 2080 | + |
| 2081 | + let (index1, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap(); |
| 2082 | + let (index2, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap(); |
| 2083 | + let (index3, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap(); |
| 2084 | + assert!(index1 == 2); |
| 2085 | + assert!(index2 == 0); |
| 2086 | + assert!(index3 == 2); |
| 2087 | + } |
| 2088 | + |
| 2089 | + #[test] |
| 2090 | + fn test_select_timeout() { |
| 2091 | + let (tx1, rx1) = channel(); |
| 2092 | + let ir1 = InstanceReceiver::new(rx1, 0); |
| 2093 | + let (tx2, rx2) = channel(); |
| 2094 | + let ir2 = InstanceReceiver::new(rx2, 0); |
| 2095 | + |
| 2096 | + thread::spawn(move || { |
| 2097 | + let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap()); |
| 2098 | + // Block the thread as sending does not block the current thread |
| 2099 | + thread::sleep(time::Duration::from_millis(10)); |
| 2100 | + let _ = tx2.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap()); |
| 2101 | + }); |
| 2102 | + |
| 2103 | + let d = time::Duration::from_millis(500); |
| 2104 | + let (index1, _) = Jvm::select_timeout(&[&ir1, &ir2], &d).unwrap(); |
| 2105 | + let (index2, _) = Jvm::select_timeout(&[&ir1, &ir2], &d).unwrap(); |
| 2106 | + assert!(Jvm::select_timeout(&[&ir1, &ir2], &d).is_err()); |
| 2107 | + dbg!(index1); |
| 2108 | + dbg!(index2); |
| 2109 | + assert!(index1 == 0); |
| 2110 | + assert!(index2 == 1); |
| 2111 | + } |
| 2112 | + |
2023 | 2113 | fn validate_type(ia: InvocationArg, class: &str) {
|
2024 | 2114 | let b = match ia {
|
2025 | 2115 | _s @ InvocationArg::Java { .. } => false,
|
|
0 commit comments