[3/7] Lockfile.

Message ID e0af7bafad94bf9d146be76842d41fadfe24be23.1700222403.git.mjires@suse.cz
State New
Headers
Series lto: Incremental LTO. |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Testing passed

Commit Message

Michal Jires Nov. 17, 2023, 8:17 p.m. UTC
  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.
---
 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
  

Comments

Jan Hubicka Dec. 29, 2023, 9:23 p.m. UTC | #1
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
>
  
Michal Jires Jan. 9, 2024, 5:10 p.m. UTC | #2
Hi,
> 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?

I tried to test _locking implementation with both mingw and msys2, in both
cases fcntl was present and _locking was not. Admittedly I was unable to
finish bootstrap without errors, so I might have been doing something wrong.

So I didn't include _locking implementation, because I was unable to test it,
and I am unsure whether we even have supported host which would require it.

Michal
  

Patch

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