Source for file lockfile-defs.php

Documentation is available at lockfile-defs.php

  1. <?php
  2. /* ******************************************************************** */
  3. /* CATALYST PHP Source Code */
  4. /* -------------------------------------------------------------------- */
  5. /* This program is free software; you can redistribute it and/or modify */
  6. /* it under the terms of the GNU General Public License as published by */
  7. /* the Free Software Foundation; either version 2 of the License, or */
  8. /* (at your option) any later version. */
  9. /* */
  10. /* This program is distributed in the hope that it will be useful, */
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  13. /* GNU General Public License for more details. */
  14. /* */
  15. /* You should have received a copy of the GNU General Public License */
  16. /* along with this program; if not, write to: */
  17. /* The Free Software Foundation, Inc., 59 Temple Place, Suite 330, */
  18. /* Boston, MA 02111-1307 USA */
  19. /* -------------------------------------------------------------------- */
  20. /* */
  21. /* Filename: lockfile-defs.php */
  22. /* Author: Paul Waite */
  23. /* Description: Provides a lockfile facility for processes which */
  24. /* require them. Handles creating and checking lockfiles */
  25. /* and removing if processes are defunct etc. */
  26. /* */
  27. /* ******************************************************************** */
  28. /** @package file */
  29. include_once("file-defs.php");
  30.  
  31. // ----------------------------------------------------------------------
  32. // Lockfile error codes..
  33.  
  34. /** Lockfile created ok */
  35. ("LCK_E_OK", 0);
  36. /** Lockfile */
  37. ("LCK_E_CREFAIL", 100);
  38. /** Lockfile process was killed */
  39. ("LCK_E_KILLED", 101);
  40. /** Lockfile process was killed with -9 */
  41. ("LCK_E_KILLED9", 102);
  42. /** Lockfile process could not be killed */
  43. ("LCK_E_IMMORTAL", 103);
  44. /** Lockfile is orphaned (no associated process) */
  45. ("LCK_E_ORPHAN", 104);
  46. /** Lockfile was frozen */
  47. ("LCK_E_FROZEN", 105);
  48. /** Lockfile could not be read */
  49. ("LCK_E_READFAIL", 106);
  50.  
  51. /** Some error messages which can be associated with the codes. */
  52. = array(
  53. LCK_E_OK => "No error",
  54. LCK_E_CREFAIL => "Failed to create lockfile",
  55. LCK_E_KILLED => "Process killed",
  56. LCK_E_KILLED9 => "Process killed (-9)",
  57. LCK_E_IMMORTAL => "Process is immortal",
  58. LCK_E_ORPHAN => "Orphaned lockfile removed",
  59. LCK_E_FROZEN => "Process frozen",
  60. LCK_E_READFAIL => "Failed to read lockfile"
  61. );
  62.  
  63. // ----------------------------------------------------------------------
  64. /**
  65. * A class to handle a lockfile for a running process. The idea is you
  66. * create one of these for a process each time you run it. If the lockfile
  67. * already exists, then
  68. * @package file
  69. */
  70. class lockfile {
  71. /** Name of the lockfile to create */
  72.  
  73. var $lockfilename = "";
  74. /** Name of freeze lockfile to create (internal) */
  75.  
  76. var $freezefilename = "";
  77. /** Process ID of process lockfile is for */
  78.  
  79. var $pid = "";
  80. /** Lockfile age at which we should assume process is hung */
  81.  
  82. var $killsecs = 0;
  83. /** Lockfile age at which we should stop trying to kill hung process */
  84.  
  85. var $freezesecs = 0;
  86. /** Minutes process has been locked for */
  87.  
  88. var $lock_mins = 0;
  89. /** Latest error message */
  90.  
  91. var $messages = "";
  92. /** Latest error code */
  93.  
  94. var $errorcode = 0;
  95. /** True if the lockfile exists */
  96.  
  97. var $exists = false;
  98. /** True if the freeze lockfile exists */
  99.  
  100. var $frozen = false;
  101. // ....................................................................
  102. /**
  103. * Make a new lockfile handler object.
  104. * @param string $lockfilename Name of the lockfile
  105. * @param string $lockfiledir Directory to create lockfile in
  106. * @param integer $pid Optional process ID (defaults to current pid)
  107. */
  108. function lockfile($lockfilename="", $lockfiledir="/tmp", $pid="") {
  109. if ($lockfilename == "") {
  110. $lockfilename = unique_filename("monitor", "LCK");
  111. }
  112. $this->lockfilename = $lockfiledir . "/" . $lockfilename;
  113. $this->freezefilename = $lockfiledir . "/" . $lockfilename . ".ERR";
  114. if ($pid == "") {
  115. $pid = posix_getpid();
  116. }
  117. $this->pid = $pid;
  118. // Set lockfile statuses..
  119. $this->exists = file_exists($this->lockfilename);
  120. $this->frozen = file_exists($this->freezefilename);
  121. } // lockfile
  122. // ....................................................................
  123. /**
  124. * Set the time limits. Some commonsense has to be applied here. You
  125. * should pick times, in mins, which are sensible according to how
  126. * frequently you are going to be checking the lockfiles. If, for
  127. * example you pick killmins=5 and freezemins=10 and only run this
  128. * every hour, then you will never give it chance to kill a hung
  129. * process between the 5 and 10 mins mark. A better choice for that
  130. * would be killmins=30 freezemins=130.
  131. * @param integer $killmins Time after which process is assumed hung
  132. * @param integer $freezemins Time after which we stop trying to kill it
  133. */
  134. function set_timelimits($killmins=0, $freezemins=0) {
  135. $this->killsecs = $killmins * 60;
  136. $this->freezesecs = $freezemins * 60;
  137. } // set_timelimits
  138. // ....................................................................
  139. /** Internal method to actually create the lockfile.
  140. * @return boolean True if the lockfile was created
  141. * @access private
  142. */
  143. function create_lockfile() {
  144. $LCK = new quickfile($this->lockfilename, $this->pid);
  145. $this->exists = $LCK->created;
  146. if (!$this->exists) {
  147. $this->error = LCK_E_CREFAIL;
  148. }
  149. return $this->exists;
  150. } // create_lockfile
  151. // ....................................................................
  152. /**
  153. * Return any lockfile error message
  154. * @return string Any error message associated with the lockfile
  155. */
  156. function errormsg() {
  157. global $LCKerrormsg;
  158. $msg = "";
  159. if (isset($LCKerrormsg[$this->errorcode])) {
  160. $msg = $LCKerrormsg[$this->errorcode]
  161. . " [" . $this->lock_mins . "mins]";
  162. if ($this->pid != "") {
  163. $msg .= " (pid=" . $this->pid . ")";
  164. }
  165. }
  166. return $msg;
  167. } // errormsg
  168. // ....................................................................
  169. /**
  170. * Create the lockfile. We only do this, obviously, if it doesn't
  171. * already exist. If it DOES exist, then we make a lot of checks. If
  172. * time-limits are set we possibly try to kill the process and remove
  173. * the lockfile before creating our new one.
  174. * If we created a lockfile then we return true, and this measn the
  175. * calling process should feel free to run. If we return false, then
  176. * either the lock is valid, or an error condition is present, and
  177. * the calling process should about/exit without running.
  178. * @return boolean True if lockfile was created successfully, else false.
  179. */
  180. function create() {
  181. $lockstatus = false;
  182.  
  183. if (!$this->exists) {
  184. // Create brand new lockfile..
  185. $lockstatus = $this->create_lockfile();
  186. }
  187. else {
  188. // Lockfile exists, check it out..
  189. $LCK = new inputfile($this->lockfilename);
  190. if ($LCK->opened) {
  191. $this->pid = $LCK->readln();
  192. $LCK->closefile();
  193.  
  194. $ts_locked = filemtime($this->lockfilename);
  195. $lockedfor = time() - $ts_locked;
  196. $this->lock_mins = floor($lockedfor / 60);
  197.  
  198. // Are we in the killing zone?...
  199. if ($this->killsecs > 0 && $lockedfor >= $this->killsecs && $lockedfor < $this->freezesecs ) {
  200. // Check if process exists and kill if so..
  201. if ($this->pid != "") {
  202. $ps = `ps --no-headers -p $this->pid`;
  203. if (trim($ps) != "") {
  204. exec("kill $this->pid");
  205. sleep(3);
  206. // Was it killed?...
  207. $ps = `ps --no-headers -p $this->pid`;
  208. if (trim($ps) == "") {
  209. $this->errorcode = LCK_E_KILLED;
  210. if (file_exists($this->lockfilename)) {
  211. unlink($this->lockfilename);
  212. }
  213. // Try to create the lockfile now..
  214. $lockstatus = $this->create_lockfile();
  215. }
  216. else {
  217. exec("kill -9 $this->pid");
  218. sleep(3);
  219. // Was it killed with extreme predjudice?...
  220. $ps = `ps --no-headers -p $this->pid`;
  221. if (trim($ps) == "") {
  222. $this->errorcode = LCK_E_KILLED9;
  223. if (file_exists($this->lockfilename)) {
  224. unlink($this->lockfilename);
  225. }
  226. // Try to create the lockfile now..
  227. $lockstatus = $this->create_lockfile();
  228. }
  229. else {
  230. $this->errorcode = LCK_E_IMMORTAL;
  231. $lockstatus = false;
  232. }
  233. }
  234. }
  235. else {
  236. // Remove orphaned lockfile..
  237. if (unlink($this->lockfilename)) {
  238. $this->errorcode = LCK_E_ORPHAN;
  239. }
  240. // Try to create the lockfile now..
  241. $lockstatus = $this->create_lockfile();
  242. }
  243. }
  244. }
  245. // Are we at the end of our patience?...
  246. elseif ($this->freezesecs > 0 && $lockedfor >= $this->freezesecs) {
  247. if (!$this->frozen) {
  248. $ERR = new quickfile($this->freezefilename);
  249. $this->errorcode = LCK_E_FROZEN;
  250. $this->frozen = true;
  251. $lockstatus = false;
  252. }
  253. }
  254. }
  255. else {
  256. // A rather unexpected error, but possible if somebody
  257. // messes with file permissions for example..
  258. $this->errorcode = LCK_E_READFAIL;
  259. }
  260. }
  261. // Return status. If true then we created the lockfile and
  262. // the calling process can go ahead. If false then either the
  263. // lockfile is present, or an error occurred, so the calling
  264. // process should not go ahead.
  265. return $lockstatus;
  266. } // create
  267. // ....................................................................
  268. /**
  269. * Remove the lockfile. Can't do this if the lock is frozen, which
  270. * is deemed to require manual intervention.
  271. * @return boolean True if the lock was removed successfully.
  272. */
  273. function remove() {
  274. $res = false;
  275. if ($this->exists) {
  276. if (!$this->frozen) {
  277. $res = unlink($this->lockfilename);
  278. }
  279. }
  280. else {
  281. // Already removed somehow..
  282. $res = true;
  283. }
  284. return $res;
  285. } // remove
  286.  
  287. } // lockfile class
  288. // ----------------------------------------------------------------------
  289.  
  290. ?>

Documentation generated by phpDocumentor 1.3.0RC3