Hi, > This patch implements lockfile used for incremental LTO. > > Bootstrapped/regtested on x86_64-pc-linux-gnu > > gcc/ChangeLog: > > * Makefile.in: Add lockfile.o. > * lockfile.cc: New file. > * lockfile.h: New file.
I can't approve it, but overall it looks good to me. We also have locking in gcov-io, but it is probably not that practical to keep these shared, since gcov-io is also built into runtime. You do not implement GCOV_LINKED_WITH_LOCKING patch, does locking work with mingw? Or we only build gcc with cygwin emulation layer these days? Honza > --- > gcc/Makefile.in | 5 +- > gcc/lockfile.cc | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ > gcc/lockfile.h | 85 ++++++++++++++++++++++++++++++ > 3 files changed, 224 insertions(+), 2 deletions(-) > create mode 100644 gcc/lockfile.cc > create mode 100644 gcc/lockfile.h > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index 7b7a4ff789a..2c527245c81 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1831,7 +1831,7 @@ ALL_HOST_BACKEND_OBJS = $(GCC_OBJS) $(OBJS) > $(OBJS-libcommon) \ > $(OBJS-libcommon-target) main.o c-family/cppspec.o \ > $(COLLECT2_OBJS) $(EXTRA_GCC_OBJS) $(GCOV_OBJS) $(GCOV_DUMP_OBJS) \ > $(GCOV_TOOL_OBJS) $(GENGTYPE_OBJS) gcc-ar.o gcc-nm.o gcc-ranlib.o \ > - lto-wrapper.o collect-utils.o > + lto-wrapper.o collect-utils.o lockfile.o > > # for anything that is shared use the cc1plus profile data, as that > # is likely the most exercised during the build > @@ -2359,7 +2359,8 @@ collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS) > CFLAGS-collect2.o += -DTARGET_MACHINE=\"$(target_noncanonical)\" \ > @TARGET_SYSTEM_ROOT_DEFINE@ > > -LTO_WRAPPER_OBJS = lto-wrapper.o collect-utils.o ggc-none.o > +LTO_WRAPPER_OBJS = lto-wrapper.o collect-utils.o ggc-none.o lockfile.o > + > lto-wrapper$(exeext): $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBDEPS) > +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o T$@ \ > $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBS) > diff --git a/gcc/lockfile.cc b/gcc/lockfile.cc > new file mode 100644 > index 00000000000..9440e8938f3 > --- /dev/null > +++ b/gcc/lockfile.cc > @@ -0,0 +1,136 @@ > +/* File locking. > + Copyright (C) 2009-2023 Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify it under > +the terms of the GNU General Public License as published by the Free > +Software Foundation; either version 3, or (at your option) any later > +version. > + > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY > +WARRANTY; without even the implied warranty of MERCHANTABILITY or > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > +for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +#include "config.h" > +#include "system.h" > + > +#include "lockfile.h" > + > + > +/* Unique write lock. No other lock can be held on this lockfile. > + Blocking call. */ > +int > +lockfile::lock_write () > +{ > + fd = open (filename.c_str (), O_RDWR | O_CREAT, 0666); > + if (fd < 0) > + return -1; > + > +#if HAVE_FCNTL_H > + struct flock s_flock; > + > + s_flock.l_whence = SEEK_SET; > + s_flock.l_start = 0; > + s_flock.l_len = 0; > + s_flock.l_pid = getpid (); > + s_flock.l_type = F_WRLCK; > + > + while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) > + continue; > +#endif > + return 0; > +} > + > +/* Unique write lock. No other lock can be held on this lockfile. > + Only locks if this filelock is not locked by any other process. > + Return whether locking was successful. */ > +int > +lockfile::try_lock_write () > +{ > + fd = open (filename.c_str (), O_RDWR | O_CREAT, 0666); > + if (fd < 0) > + return -1; > + > +#if HAVE_FCNTL_H > + struct flock s_flock; > + > + s_flock.l_whence = SEEK_SET; > + s_flock.l_start = 0; > + s_flock.l_len = 0; > + s_flock.l_pid = getpid (); > + s_flock.l_type = F_WRLCK; > + > + if (fcntl (fd, F_SETLK, &s_flock) == -1) > + { > + close (fd); > + fd = -1; > + return 1; > + } > +#endif > + return 0; > +} > + > +/* Shared read lock. Only read lock can be held concurrently. > + If write lock is already held by this process, it will be > + changed to read lock. > + Blocking call. */ > +int > +lockfile::lock_read () > +{ > + fd = open (filename.c_str (), O_RDWR | O_CREAT, 0666); > + if (fd < 0) > + return -1; > + > +#if HAVE_FCNTL_H > + struct flock s_flock; > + > + s_flock.l_whence = SEEK_SET; > + s_flock.l_start = 0; > + s_flock.l_len = 0; > + s_flock.l_pid = getpid (); > + s_flock.l_type = F_RDLCK; > + > + while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) > + continue; > +#endif > + return 0; > +} > + > +/* Unlock all previously placed locks. */ > +void > +lockfile::unlock () > +{ > + if (fd < 0) > + { > +#if HAVE_FCNTL_H > + struct flock s_flock; > + > + s_flock.l_whence = SEEK_SET; > + s_flock.l_start = 0; > + s_flock.l_len = 0; > + s_flock.l_pid = getpid (); > + s_flock.l_type = F_UNLCK; > + > + fcntl (fd, F_SETLK, &s_flock); > +#endif > + close (fd); > + fd = -1; > + } > +} > + > +/* Are lockfiles supported? */ > +bool > +lockfile::lockfile_supported () > +{ > +#if HAVE_FCNTL_H > + return true; > +#else > + return false; > +#endif > +} > diff --git a/gcc/lockfile.h b/gcc/lockfile.h > new file mode 100644 > index 00000000000..afcbaf599c1 > --- /dev/null > +++ b/gcc/lockfile.h > @@ -0,0 +1,85 @@ > +/* File locking. > + Copyright (C) 2009-2023 Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify it under > +the terms of the GNU General Public License as published by the Free > +Software Foundation; either version 3, or (at your option) any later > +version. > + > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY > +WARRANTY; without even the implied warranty of MERCHANTABILITY or > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > +for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +#ifndef LOCKFILE_H > +#define LOCKFILE_H > + > +#include <string> > + > +/* Used to synchronize across multiple processes. */ > +class lockfile { > +public: > + /* Default constructor. */ > + lockfile (): fd (-1) > + {} > + /* Intended constructor for use. Filename should not be used for anything > + other than locking to prevent unintentional unlock. */ > + lockfile (std::string filename): lockfile () > + { > + this->filename = std::move (filename); > + } > + lockfile (lockfile const& o): lockfile (o.filename) > + {} > + > + void operator=(lockfile o) > + { > + unlock (); > + this->filename = o.filename; > + this->fd = o.fd; > + o.fd = -1; > + } > + > + /* Unique write lock. No other lock can be held on this lockfile. > + Blocking call. */ > + int > + lock_write (); > + > + /* Unique write lock. No other lock can be held on this lockfile. > + Only locks if this filelock is not locked by any other process. > + Return whether locking was successful. */ > + int > + try_lock_write (); > + > + /* Shared read lock. Only read lock can be held concurrently. > + If write lock is already held by this process, it will be > + changed to read lock. > + Blocking call. */ > + int > + lock_read (); > + > + /* Unlock all previously placed locks. */ > + void > + unlock (); > + > + /* Returns whether any lock is held. */ > + bool > + locked () > + { > + return fd < 0; > + } > + > + /* Are lockfiles supported? */ > + static bool > + lockfile_supported (); > +private: > + std::string filename; > + int fd; > +}; > + > +#endif > -- > 2.42.1 >