diff options
| author | Paulo Casaretto <pcasaretto@gmail.com> | 2026-01-22 19:23:35 +0000 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-01-22 12:15:46 -0800 |
| commit | dbdcab6b89ea86fe58ece01bbb7be297ff23b2c4 (patch) | |
| tree | 07895f879fe1891dbe2ec9689f0df885772b05e4 /lockfile.h | |
| parent | c4a0c8845e2426375ad257b6c221a3a7d92ecfda (diff) | |
| download | git-dbdcab6b89ea86fe58ece01bbb7be297ff23b2c4.tar.xz | |
lockfile: add PID file for debugging stale locks
When a lock file is held, it can be helpful to know which process owns
it, especially when debugging stale locks left behind by crashed
processes. Add an optional feature that creates a companion PID file
alongside each lock file, containing the PID of the lock holder.
For a lock file "foo.lock", the PID file is named "foo~pid.lock". The
tilde character is forbidden in refnames and allowed in Windows
filenames, which guarantees no collision with the refs namespace
(e.g., refs "foo" and "foo~pid" cannot both exist). The file contains
a single line in the format "pid <value>" followed by a newline.
The PID file is created when a lock is acquired (if enabled), and
automatically cleaned up when the lock is released (via commit or
rollback). The file is registered as a tempfile so it gets cleaned up
by signal and atexit handlers if the process terminates abnormally.
When a lock conflict occurs, the code checks for an existing PID file
and, if found, uses kill(pid, 0) to determine if the process is still
running. This allows providing context-aware error messages:
Lock is held by process 12345. Wait for it to finish, or remove
the lock file to continue.
Or for a stale lock:
Lock was held by process 12345, which is no longer running.
Remove the stale lock file to continue.
The feature is controlled via core.lockfilePid configuration (boolean).
Defaults to false. When enabled, PID files are created for all lock
operations.
Existing PID files are always read when displaying lock errors,
regardless of the core.lockfilePid setting. This ensures helpful
diagnostics even when the feature was previously enabled and later
disabled.
Signed-off-by: Paulo Casaretto <pcasaretto@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'lockfile.h')
| -rw-r--r-- | lockfile.h | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/lockfile.h b/lockfile.h index 1bb9926497..e7233f28de 100644 --- a/lockfile.h +++ b/lockfile.h @@ -119,6 +119,7 @@ struct lock_file { struct tempfile *tempfile; + struct tempfile *pid_tempfile; }; #define LOCK_INIT { 0 } @@ -127,6 +128,22 @@ struct lock_file { #define LOCK_SUFFIX ".lock" #define LOCK_SUFFIX_LEN 5 +/* + * PID file naming: for a lock file "foo.lock", the PID file is "foo~pid.lock". + * The tilde is forbidden in refnames and allowed in Windows filenames, avoiding + * namespace collisions (e.g., refs "foo" and "foo~pid" cannot both exist). + */ +#define LOCK_PID_INFIX "~pid" +#define LOCK_PID_INFIX_LEN 4 + +/* Maximum length for PID file content */ +#define LOCK_PID_MAXLEN 32 + +/* + * Whether to create PID files alongside lock files. + * Configured via core.lockfilePid (boolean). + */ +extern int lockfile_pid_enabled; /* * Flags @@ -169,12 +186,12 @@ struct lock_file { * handling, and mode are described above. */ int hold_lock_file_for_update_timeout_mode( - struct lock_file *lk, const char *path, - int flags, long timeout_ms, int mode); + struct lock_file *lk, const char *path, + int flags, long timeout_ms, int mode); static inline int hold_lock_file_for_update_timeout( - struct lock_file *lk, const char *path, - int flags, long timeout_ms) + struct lock_file *lk, const char *path, + int flags, long timeout_ms) { return hold_lock_file_for_update_timeout_mode(lk, path, flags, timeout_ms, 0666); @@ -186,15 +203,14 @@ static inline int hold_lock_file_for_update_timeout( * argument and error handling are described above. */ static inline int hold_lock_file_for_update( - struct lock_file *lk, const char *path, - int flags) + struct lock_file *lk, const char *path, int flags) { return hold_lock_file_for_update_timeout(lk, path, flags, 0); } static inline int hold_lock_file_for_update_mode( - struct lock_file *lk, const char *path, - int flags, int mode) + struct lock_file *lk, const char *path, + int flags, int mode) { return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode); } @@ -319,13 +335,10 @@ static inline int commit_lock_file_to(struct lock_file *lk, const char *path) /* * Roll back `lk`: close the file descriptor and/or file pointer and - * remove the lockfile. It is a NOOP to call `rollback_lock_file()` - * for a `lock_file` object that has already been committed or rolled - * back. No error will be returned in this case. + * remove the lockfile and any associated PID file. It is a NOOP to + * call `rollback_lock_file()` for a `lock_file` object that has already + * been committed or rolled back. No error will be returned in this case. */ -static inline int rollback_lock_file(struct lock_file *lk) -{ - return delete_tempfile(&lk->tempfile); -} +int rollback_lock_file(struct lock_file *lk); #endif /* LOCKFILE_H */ |
