package hack_parallel

  1. Overview
  2. Docs
Parallel and shared memory library

Install

Dune Dependency

Authors

Maintainers

Sources

1.0.1.tar.gz
md5=ba7c72bc207e326b72e294fc76f6ad2c
sha512=5020d47f97bea2f88e2a40411894d03232a7f2282606926c93c7d4c96d72e94a966be852897a9b16f7e0893ba376512045abb9d93020a7c03c3def4f3d918f8e

doc/src/hack_parallel.utils/lock.ml.html

Source file lock.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
(**
 * Copyright (c) 2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 *)

let lock_fds = ref SMap.empty

(**
 * Basic lock operations.
 *
 * We use these for two reasons:
 * 1. making sure we are only running one instance of hh_server per person on a given dev box
 * 2. giving a way to hh_client to check if a server is running.
 *)

let register_lock lock_file =
  let _ = Sys_utils.mkdir_no_fail (Filename.dirname lock_file) in
  Sys_utils.with_umask 0o111 begin fun () ->
    let fd = Unix.descr_of_out_channel (open_out lock_file) in
    let st = Unix.fstat fd in
    lock_fds := SMap.add lock_file (fd, st) !lock_fds;
    fd
  end

(**
 * Grab or check if a file lock is available.
 *
 * Returns true if the lock is/was available, false otherwise.
 *)
let _operations lock_file op : bool =
  try
    let fd = match SMap.get lock_file !lock_fds with
      | None -> register_lock lock_file
      | Some (fd, st) ->
          let identical_file =
            try
              (* Note: I'm carefully avoiding opening another fd to the
               * lock_file when doing this check, because closing any file
               * descriptor to a given file will release the locks on *all*
               * file descriptors that point to that file. Fortunately, stat()
               * gets us our information without opening a fd *)
              let current_st = Unix.stat lock_file in
              Unix.(st.st_dev = current_st.st_dev &&
                st.st_ino = current_st.st_ino)
            with _ ->
              false
          in
          if not (Sys.win32 || identical_file) then
            (* Looks like someone (tmpwatch?) deleted the lock file; don't
             * create another one, because our socket is probably gone too.
             * We are dead in the water. *)
            raise Exit
          else
            fd
    in
    let _ =
      try Unix.lockf fd op 1
      with _ when Sys.win32 && (op = Unix.F_TLOCK || op = Unix.F_TEST) ->
          (* On Windows, F_TLOCK and F_TEST fail if we have the lock ourself *)
          (* However, we then are the only one to be able to write there. *)
          ignore (Unix.lseek fd 0 Unix.SEEK_SET : int);
          (* If we don't have the lock, the following 'write' will
             throw an exception. *)
          let wb = Unix.write fd (Bytes.make 1 ' ') 0 1 in
          (* When not throwing an exception, the current
             implementation of `Unix.write` always return `1`. But let's
             be protective against semantic changes, and better fails
             than wrongly assume that we own a lock. *)
          assert (wb = 1) in
    true
  with _ ->
    false

(**
 * Grabs the file lock and returns true if it the lock was grabbed
 *)
let grab lock_file : bool = _operations lock_file Unix.F_TLOCK

(**
 * Releases a file lock.
 *)
let release lock_file : bool = _operations lock_file Unix.F_ULOCK

let blocking_grab_then_release lock_file =
  ignore (_operations lock_file Unix.F_LOCK);
  ignore (release lock_file)


(**
 * Gets the server instance-unique integral fd for a given lock file.
 *)
let fd_of lock_file : int =
  match SMap.get lock_file !lock_fds with
    | None -> -1
    | Some fd -> Obj.magic fd

(**
 * Check if the file lock is available without grabbing it.
 * Returns true if the lock is free.
 *)
let check lock_file : bool = _operations lock_file Unix.F_TEST
OCaml

Innovation. Community. Security.