1pub mod error;
24
25#[cfg(target_os = "macos")]
26extern crate libc;
27#[cfg(any(target_os = "linux", target_os ="android"))]
28extern crate nix;
29extern crate thiserror;
30#[cfg(target_os = "windows")]
31extern crate widestring;
32#[cfg(target_os = "windows")]
33extern crate winapi;
34
35pub use self::inner::*;
36
37#[cfg(target_os = "windows")]
38mod inner {
39 use error::{Result, SingleInstanceError};
40 use std::ptr;
41 use widestring::WideCString;
42 use winapi::shared::winerror::{ERROR_ALREADY_EXISTS, ERROR_INVALID_HANDLE};
43 use winapi::um::errhandlingapi::GetLastError;
44 use winapi::um::handleapi::CloseHandle;
45 use winapi::um::synchapi::CreateMutexW;
46 use winapi::um::winnt::HANDLE;
47
48 pub struct SingleInstance {
50 handle: Option<HANDLE>,
51 }
52
53 unsafe impl Send for SingleInstance {}
54 unsafe impl Sync for SingleInstance {}
55
56 impl SingleInstance {
57 pub fn new(name: &str) -> Result<Self> {
59 let name = WideCString::from_str(name)?;
60 unsafe {
61 let handle = CreateMutexW(ptr::null_mut(), 0, name.as_ptr());
62 let last_error = GetLastError();
63
64 if handle.is_null() || handle == ERROR_INVALID_HANDLE as _ {
66 Err(SingleInstanceError::MutexError(last_error))
67 } else if last_error == ERROR_ALREADY_EXISTS {
68 CloseHandle(handle);
69 Ok(SingleInstance { handle: None })
70 } else {
71 Ok(SingleInstance {
72 handle: Some(handle),
73 })
74 }
75 }
76 }
77
78 pub fn is_single(&self) -> bool {
80 self.handle.is_some()
81 }
82 }
83
84 impl Drop for SingleInstance {
85 fn drop(&mut self) {
86 if let Some(handle) = self.handle.take() {
87 unsafe {
88 CloseHandle(handle);
89 }
90 }
91 }
92 }
93}
94
95#[cfg(any(target_os = "linux", target_os="android"))]
96mod inner {
97 use std::io::ErrorKind;
98 use std::os::unix::prelude::RawFd;
99 use nix::unistd;
100 use std::os::unix::net::{UnixListener, UnixStream};
101 use std::os::fd::IntoRawFd;
102 use std::io::Result;
103
104 pub struct SingleInstance {
106 socket: Option<RawFd>,
107 single: bool,
108 }
109
110 impl SingleInstance {
111 pub fn new(name: &str) -> Result<Self> {
113 let socket_path = "/tmp/".to_string() + name + ".sock";
114 let single;
115
116 let socket = match UnixListener::bind(&socket_path) {
117 Ok(socket) => {
118 single = true;
119 Some(socket.into_raw_fd())
120 },
121 Err(ref e) if e.kind() == ErrorKind::AddrInUse => {
122 match UnixStream::connect(&socket_path) {
124 Ok(_) => {
125 single = false;
127 None
128 },
129 Err(_) => {
130 std::fs::remove_file(&socket_path)?;
132 match UnixListener::bind(&socket_path) {
133 Ok(socket) => {
134 single = true;
135 Some(socket.into_raw_fd())
136 },
137 Err(_) => {
138 single = false;
139 None
140 },
141 }
142 },
143 }
144 },
145 Err(_) => {
146 single = false;
147 None
148 },
149 };
150
151 Ok(Self {
152 socket,
153 single,
154 })
155 }
156
157 pub fn is_single(&self) -> bool {
159 self.single
160 }
161 }
162
163 impl Drop for SingleInstance {
164 fn drop(&mut self) {
165 if let Some(sock) = self.socket {
166 let _ = unistd::close(sock);
167 }
168 }
169 }
170}
171
172#[cfg(target_os = "macos")]
173mod inner {
174 use error::Result;
175 use libc::{__error, flock, EWOULDBLOCK, LOCK_EX, LOCK_NB};
176 use std::fs::File;
177 use std::os::unix::io::AsRawFd;
178 use std::path::Path;
179
180 pub struct SingleInstance {
182 _file: File,
183 is_single: bool,
184 }
185
186 impl SingleInstance {
187 pub fn new(name: &str) -> Result<Self> {
189 let path = Path::new(name);
190 let file = if path.exists() {
191 File::open(path)?
192 } else {
193 File::create(path)?
194 };
195 unsafe {
196 let rc = flock(file.as_raw_fd(), LOCK_EX | LOCK_NB);
197 let is_single = rc == 0 || EWOULDBLOCK != *__error();
198 Ok(Self {
199 _file: file,
200 is_single,
201 })
202 }
203 }
204
205 pub fn is_single(&self) -> bool {
207 self.is_single
208 }
209 }
210}
211
212#[test]
213fn test_single_instance() {
214 {
215 let instance_a = SingleInstance::new("aa2d0258-ffe9-11e7-ba89-0ed5f89f718b").unwrap();
216 assert!(instance_a.is_single());
217 let instance_b = SingleInstance::new("aa2d0258-ffe9-11e7-ba89-0ed5f89f718b").unwrap();
218 assert!(!instance_b.is_single());
219 }
220 let instance_c = SingleInstance::new("aa2d0258-ffe9-11e7-ba89-0ed5f89f718b").unwrap();
221 assert!(instance_c.is_single());
222}