(* $Id: netmcore_mutex.ml 1570 2011-04-08 14:47:16Z gerd $ *) type mutex_type = [ `Normal | `Errorcheck | `Recursive ] type mutex = { is_dummy : bool; mtype : mutex_type; mutable lock : Netmcore_sem.semaphore; mutable proplock : Netmcore_sem.semaphore; mutable owner : int; (* pid *) mutable number : int; } let dummy() = { is_dummy = true; mtype = `Normal; lock = Netmcore_sem.dummy(); proplock = Netmcore_sem.dummy(); owner = 0; number = 0; } let create mut mtype = let mutex_orig = { is_dummy = false; mtype = mtype; lock = Netmcore_sem.dummy(); proplock = Netmcore_sem.dummy(); owner = 0; number = 0; } in let mutex = Netmcore_heap.add mut mutex_orig in Netmcore_heap.pin mut mutex; let lock = Netmcore_sem.create mut 1 in mutex.lock <- lock; if mtype <> `Normal then ( let proplock = Netmcore_sem.create mut 1 in mutex.proplock <- proplock; ); mutex let serialized sem f = Netmcore_sem.wait sem Netsys_posix.SEM_WAIT_BLOCK; try let r = f() in Netmcore_sem.post sem; r with | error -> Netmcore_sem.post sem; raise error let lock mutex = if mutex.is_dummy then failwith "Netmcore_mutex.lock: dummy mutex"; match mutex.mtype with | `Normal -> Netmcore_sem.wait mutex.lock Netsys_posix.SEM_WAIT_BLOCK | `Errorcheck -> let pid = Unix.getpid() in serialized mutex.proplock (fun () -> if mutex.owner = pid then failwith "Netmcore_mutex.lock: already locked by this process" ); Netmcore_sem.wait mutex.lock Netsys_posix.SEM_WAIT_BLOCK; serialized mutex.proplock (fun () -> mutex.owner <- pid ) | `Recursive -> let pid = Unix.getpid() in let need_lock = serialized mutex.proplock (fun () -> mutex.owner <> pid || ( mutex.number <- mutex.number + 1; false ) ) in if need_lock then ( Netmcore_sem.wait mutex.lock Netsys_posix.SEM_WAIT_BLOCK; serialized mutex.proplock (fun () -> mutex.owner <- pid; mutex.number <- 1; ) ) let unlock mutex = if mutex.is_dummy then failwith "Netmcore_mutex.unlock: dummy mutex"; match mutex.mtype with | `Normal -> Netmcore_sem.post mutex.lock | `Errorcheck -> let pid = Unix.getpid() in serialized mutex.proplock (fun () -> if mutex.owner <> pid then failwith "Netmcore_mutex.unlock: not locked by this process"; Netmcore_sem.post mutex.lock; mutex.owner <- 0; ) | `Recursive -> let pid = Unix.getpid() in serialized mutex.proplock (fun () -> if mutex.owner <> pid then failwith "Netmcore_mutex.unlock: not locked by this process"; Netmcore_sem.post mutex.lock; mutex.number <- mutex.number - 1; if mutex.number = 0 then mutex.owner <- 0 ) let destroy mutex = if not mutex.is_dummy then ( Netmcore_sem.destroy mutex.lock; Netmcore_sem.destroy mutex.proplock; )