• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

lockfile.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "ink_platform.h"
00025 #include "ink_lockfile.h"
00026 
00027 #define LOCKFILE_BUF_LEN 16     // 16 bytes should be enought for a pid
00028 
00029 int
00030 Lockfile::Open(pid_t * holding_pid)
00031 {
00032   char buf[LOCKFILE_BUF_LEN];
00033   pid_t val;
00034   int err;
00035   *holding_pid = 0;
00036 
00037 #define FAIL(x) \
00038 { \
00039   if (fd > 0) \
00040     close (fd); \
00041   return (x); \
00042 }
00043 
00044   struct flock lock;
00045   char *t;
00046   int size;
00047 
00048   fd = -1;
00049 
00050   // Try and open the Lockfile. Create it if it does not already
00051   // exist.
00052   do {
00053     fd = open(fname, O_RDWR | O_CREAT, 0644);
00054   } while ((fd < 0) && (errno == EINTR));
00055 
00056   if (fd < 0)
00057     return (-errno);
00058 
00059   // Lock it. Note that if we can't get the lock EAGAIN will be the
00060   // error we receive.
00061   lock.l_type = F_WRLCK;
00062   lock.l_start = 0;
00063   lock.l_whence = SEEK_SET;
00064   lock.l_len = 0;
00065 
00066   do {
00067     err = fcntl(fd, F_SETLK, &lock);
00068   } while ((err < 0) && (errno == EINTR));
00069 
00070   if (err < 0) {
00071     // We couldn't get the lock. Try and read the process id of the
00072     // process holding the lock from the lockfile.
00073     t = buf;
00074 
00075     for (size = 15; size > 0;) {
00076       do {
00077         err = read(fd, t, size);
00078       } while ((err < 0) && (errno == EINTR));
00079 
00080       if (err < 0)
00081         FAIL(-errno);
00082       if (err == 0)
00083         break;
00084 
00085       size -= err;
00086       t += err;
00087     }
00088 
00089     *t = '\0';
00090 
00091     // coverity[secure_coding]
00092     if (sscanf(buf, "%d\n", (int*)&val) != 1) {
00093       *holding_pid = 0;
00094     } else {
00095       *holding_pid = val;
00096     }
00097     FAIL(0);
00098   }
00099   // If we did get the lock, then set the close on exec flag so that
00100   // we don't accidently pass the file descriptor to a child process
00101   // when we do a fork/exec.
00102   do {
00103     err = fcntl(fd, F_GETFD, 0);
00104   } while ((err < 0) && (errno == EINTR));
00105 
00106   if (err < 0)
00107     FAIL(-errno);
00108 
00109   val = err | FD_CLOEXEC;
00110 
00111   do {
00112     err = fcntl(fd, F_SETFD, val);
00113   } while ((err < 0) && (errno == EINTR));
00114 
00115   if (err < 0)
00116     FAIL(-errno);
00117 
00118   // Return the file descriptor of the opened lockfile. When this file
00119   // descriptor is closed the lock will be released.
00120 
00121   return (1);                   // success
00122 
00123 #undef FAIL
00124 }
00125 
00126 int
00127 Lockfile::Get(pid_t * holding_pid)
00128 {
00129   char buf[LOCKFILE_BUF_LEN];
00130   int err;
00131   *holding_pid = 0;
00132 
00133 
00134   fd = -1;
00135 
00136   // Open the Lockfile and get the lock. If we are successful, the
00137   // return value will be the file descriptor of the opened Lockfile.
00138   err = Open(holding_pid);
00139   if (err != 1)
00140     return err;
00141 
00142   if (fd < 0) {
00143     return -1;
00144   }
00145   // Truncate the Lockfile effectively erasing it.
00146   do {
00147     err = ftruncate(fd, 0);
00148   } while ((err < 0) && (errno == EINTR));
00149 
00150   if (err < 0) {
00151     close(fd);
00152     return (-errno);
00153   }
00154   // Write our process id to the Lockfile.
00155   snprintf(buf, sizeof(buf), "%d\n", (int) getpid());
00156 
00157   do {
00158     err = write(fd, buf, strlen(buf));
00159   } while ((err < 0) && (errno == EINTR));
00160 
00161   if (err != (int) strlen(buf)) {
00162     close(fd);
00163     return (-errno);
00164   }
00165 
00166   return (1);                   // success
00167 }
00168 
00169 void
00170 Lockfile::Close(void)
00171 {
00172   if (fd != -1) {
00173     close(fd);
00174   }
00175 }
00176 
00177 //-------------------------------------------------------------------------
00178 // Lockfile::Kill() and Lockfile::KillAll()
00179 //
00180 // Open the lockfile. If we succeed it means there was no process
00181 // holding the lock. We'll just close the file and release the lock
00182 // in that case. If we don't succeed in getting the lock, the
00183 // process id of the process holding the lock is returned. We
00184 // repeatedly send the KILL signal to that process until doing so
00185 // fails. That is, until kill says that the process id is no longer
00186 // valid (we killed the process), or that we don't have permission
00187 // to send a signal to that process id (the process holding the lock
00188 // is dead and a new process has replaced it).
00189 //
00190 // INKqa11325 (Kevlar: linux machine hosed up if specific threads
00191 // killed): Unfortunately, it's possible on Linux that the main PID of
00192 // the process has been successfully killed (and is waiting to be
00193 // reaped while in a defunct state), while some of the other threads
00194 // of the process just don't want to go away.
00195 //-------------------------------------------------------------------------
00196 
00197 static void
00198 lockfile_kill_internal(pid_t init_pid, int init_sig, pid_t pid, const char * /* pname ATS_UNUSED */, int sig)
00199 {
00200   int err;
00201   int status;
00202 
00203   if (init_sig > 0) {
00204     kill(init_pid, init_sig);
00205     // Wait for children to exit
00206     do {
00207       err = waitpid(-1, &status, WNOHANG);
00208       if (err == -1) break;
00209     } while(!WIFEXITED(status) && !WIFSIGNALED(status));
00210   }
00211 
00212   do {
00213     err = kill(pid, sig);
00214   } while ((err == 0) || ((err < 0) && (errno == EINTR)));
00215 
00216 }
00217 
00218 void
00219 Lockfile::Kill(int sig, int initial_sig, const char *pname)
00220 {
00221   int err;
00222   int pid;
00223   pid_t holding_pid;
00224 
00225   err = Open(&holding_pid);
00226   if (err == 1)                 // success getting the lock file
00227   {
00228     Close();
00229   } else if (err == 0)          // someone else has the lock
00230   {
00231     pid = holding_pid;
00232     if (pid != 0) {
00233       lockfile_kill_internal(pid, initial_sig, pid, pname, sig);
00234     }
00235   }
00236 }
00237 
00238 void
00239 Lockfile::KillGroup(int sig, int initial_sig, const char *pname)
00240 {
00241   int err;
00242   pid_t pid;
00243   pid_t holding_pid;
00244 
00245   err = Open(&holding_pid);
00246   if (err == 1)                 // success getting the lock file
00247   {
00248     Close();
00249   } else if (err == 0)          // someone else has the lock
00250   {
00251     do {
00252       pid = getpgid(holding_pid);
00253     } while ((pid < 0) && (errno == EINTR));
00254 
00255     if ((pid < 0) || (pid == getpid()))
00256       pid = holding_pid;
00257 
00258     if (pid != 0) {
00259       // This way, we kill the process_group:
00260       pid = -pid;
00261       // In order to get core files from each process, please
00262       // set your core_pattern appropriately.
00263       lockfile_kill_internal(holding_pid, initial_sig, pid, pname, sig);
00264     }
00265   }
00266 }

Generated by  doxygen 1.7.1