1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef MULTIINSTANCELOCK_H
8 #define MULTIINSTANCELOCK_H
15 // These functions manage "multi-instance locks", which are a type of lock
16 // specifically designed to allow instances of an application, process, or other
17 // task to detect when other instances relevant to them are running. Each
18 // instance opens a lock and holds it for the duration of the task of interest
19 // (which may be the lifetime of the process, or a shorter period). Then while
20 // the lock is open, it can be used to check whether any other instances of the
21 // same task are currently running out of the same copy of the binary, in the
22 // context of any OS user. A process can open any number of locks, so long as
23 // they use different names. It is necessary for the process to have permission
24 // to create files in /tmp/ on POSIX systems or ProgramData\[vendor]\ on
25 // Windows, so this mechanism may not work for sandboxed processes.
27 // The implementation is based on file locking. An empty file is created in a
28 // systemwide (not per-user) location, and a shared (read) lock is taken on that
29 // file; the value that OpenMultiInstanceLock() returns is the file
30 // handle/descriptor. When you call IsOtherInstanceRunning(), it will attempt to
31 // convert that shared lock into an exclusive (write) lock. If that operation
32 // would succeed, it means that there must not be any other shared locks
33 // currently taken on that file, so we know there are no other instances
34 // running. This is a more complex design than most file locks or most other
35 // concurrency mechanisms, but it is necessary for this use case because of the
36 // requirement that an instance must be able to detect other instances that were
37 // started later than it was. If, say, a mutex were used, or another kind of
38 // exclusive lock, then the first instance that tried to take it would succeed,
39 // and be unable to tell that another instance had tried to take it later and
40 // failed. This mechanism allows any number of instances started at any time in
41 // relation to one another to always be able to detect that the others exist
42 // (although it does not allow you to know how many others exist). The lock is
43 // guaranteed to be released if the process holding it crashes or is exec'd into
44 // something else, because the file is closed when that happens. The file itself
45 // is not necessarily always deleted on POSIX, because it isn't possible (within
46 // reason) to guarantee that unlink() is called, but the file is empty and
47 // created in the /tmp directory, so should not be a serious problem.
52 using MultiInstLockHandle
= HANDLE
;
53 # define MULTI_INSTANCE_LOCK_HANDLE_ERROR INVALID_HANDLE_VALUE
55 using MultiInstLockHandle
= int;
56 # define MULTI_INSTANCE_LOCK_HANDLE_ERROR -1
60 * nameToken should be a string very briefly naming the lock you are creating
61 * creating, and it should be unique except for across multiple instances of the
62 * same application. The vendor name is included in the generated path, so it
63 * doesn't need to be present in your supplied name. Try to keep this name sort
64 * of short, ideally under about 64 characters, because creating the lock will
65 * fail if the final path string (the token + the path hash + the vendor name)
66 * is longer than the platform's maximum path and/or path component length.
68 * installPath should be the path to the directory containing the application,
69 * which will be used to form a path specific to that installation.
71 * Returns MULTI_INSTANCE_LOCK_HANDLE_ERROR upon failure, or a handle which can
72 * later be passed to the other functions declared here upon success.
74 MultiInstLockHandle
OpenMultiInstanceLock(const char* nameToken
,
75 const char16_t
* installPath
);
77 void ReleaseMultiInstanceLock(MultiInstLockHandle lock
);
79 // aResult will be set to true if another instance *was* found, false if not.
80 // Return value is true on success, false on error (and aResult won't be set).
81 bool IsOtherInstanceRunning(MultiInstLockHandle lock
, bool* aResult
);
83 // It is possible that the path we have is on a case insensitive
84 // filesystem in which case the path may vary depending on how the
85 // application is called. We want to normalize the case somehow.
86 // When aAppFile is NULL, this function returns a nsIFile with a normalized
87 // path for the currently running binary. When aAppFile is not null,
88 // this function ensures the file path is properly normalized.
89 already_AddRefed
<nsIFile
> GetNormalizedAppFile(nsIFile
* aAppFile
);
91 // Computes the file path of multi instance lock
92 // Returns true when successful - false otherwise
93 bool GetMultiInstanceLockFileName(const char* nameToken
,
94 const char16_t
* installPath
,
97 }; // namespace mozilla
99 #endif // MULTIINSTANCELOCK_H