i2pd-launch 0.5.0-beta.12

Launches i2pd with clean state
#![allow(unsafe_code)]
use std::ffi::OsString;
use std::io::Result;
use std::os::windows::ffi::OsStrExt;

use windows_sys::core::PCWSTR;
use windows_sys::Win32::Foundation::{CloseHandle, BOOL, HANDLE, WAIT_OBJECT_0, WAIT_TIMEOUT};
use windows_sys::Win32::System::Threading::{CreateSemaphoreW, ReleaseSemaphore, WaitForSingleObject};

pub const NULL_HANDLE: HANDLE = 0;

/// Vytvoří nový semafor nebo se připojí k existujícímu.
/// Vrací HANDLE přímo – žádná obalující struktura
pub fn create(initial_count: i32, max_count: i32) -> Result<HANDLE> {
   let name: Vec<u16> = OsString::from("Local\\i2pd-launch_Local_AppSemaphore_v1")
      .encode_wide()
      .chain(Some(0))
      .collect();
   let handle: HANDLE = unsafe { CreateSemaphoreW(std::ptr::null_mut(), initial_count, max_count, name.as_ptr() as PCWSTR) };
   if handle == NULL_HANDLE {
      Err(std::io::Error::last_os_error())
   } else {
      Ok(handle)
   }
}

/// Sníží hodnotu semaforu o 1. Čeká max. `timeout_ms` ms.
/// Vrací Err::TimedOut při WAIT_TIMEOUT (explicitní rozlišení od OS chyby).
pub fn acquire(handle: HANDLE, timeout_ms: u32) -> Result<HANDLE> {
   let result = unsafe { WaitForSingleObject(handle, timeout_ms) };
   if result == WAIT_OBJECT_0 {
      Ok(handle)
   } else if result == WAIT_TIMEOUT {
      // Timeout – vrátíme specifickou Windows chybu ERROR_TIMEOUT (0x5B4)
      Err(std::io::Error::new(
         std::io::ErrorKind::TimedOut,
         "Timeout waiting for a semaphore",
      ))
   } else {
      // WAIT_FAILED nebo jiná chyba
      Err(std::io::Error::last_os_error())
   }
}

/// Zvýší hodnotu semaforu o 1.
pub fn release(handle: HANDLE) -> Result<HANDLE> {
   let result: BOOL = unsafe { ReleaseSemaphore(handle, 1, std::ptr::null_mut()) };
   if result == 0 {
      Err(std::io::Error::last_os_error())
   } else {
      Ok(handle)
   }
}

/// Uzavře handle semaforu. Volající je odpovědný za to,
/// že handle po tomto volání již nepoužije.
pub fn close(handle: HANDLE) -> Result<()> {
   let result: BOOL = unsafe { CloseHandle(handle) };

   if result == 0 {
      Err(std::io::Error::last_os_error())
   } else {
      Ok(())
   }
}

#[cfg(test)]
#[path = "sem_tests.rs"]
mod sem_tests;