Skip to content

Instantly share code, notes, and snippets.

@koyhoge
Created December 8, 2011 12:54
Show Gist options
  • Save koyhoge/1446922 to your computer and use it in GitHub Desktop.
Save koyhoge/1446922 to your computer and use it in GitHub Desktop.
single_exection patched by koyhoge
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
// created by bto
// via http://blog.bz2.jp/archives/2008/05/1php.html
// http://blog.bz2.jp/archives/2008/05/singleexecution.html
class singleExecution
{
var $key = null;
var $options = array(
'begin' => true,
'lock_directory' => null,
'checks_process_existence' => true,
'do_unlock' => true,
);
function singleExecution($options = array())
{
$this->options['lock_directory'] = $this->createPath(
$this->temporaryDirectory(), $this->underscore(__CLASS__));
$this->options = array_merge($this->options, $options);
if ($this->options['begin']) {
$this->lock();
}
}
function setDoUnlock($val = true) {
$this->options['do_unlock'] = $val;
}
function createKey()
{
foreach (debug_backtrace() as $stack) {
if ($stack['file'] !== __FILE__) {
return $stack['file'] . ':' . $stack['line'];
}
}
return __FILE__ . ':' . __LINE__;
}
function createPath()
{
return join(func_get_args(), DIRECTORY_SEPARATOR);
}
function failed()
{
exit();
}
function isInvalidLock($directory)
{
if (!file_exists($directory)) {
return true;
}
if (!is_dir($directory)) {
return false;
}
$pid_file = $this->createPath($directory, 'pid');
if (!is_file($pid_file)) {
return false;
}
if (!$this->options['checks_process_existence']) {
return true;
}
return $this->processExists(intval(file_get_contents($pid_file)));
}
function lock($key = null)
{
if (!$key) {
$key = $this->createKey();
}
$this->unlockIfInvalid($key);
$lock_directory = $this->lockDirectory($key);
if (!$this->mkdir($lock_directory)) {
return $this->failed();
}
if (singleExecution::loadExtension('pcntl')) {
$this->key = $key;
pcntl_signal(SIGTERM, array($this, 'unlockExit'));
pcntl_signal(SIGHUP, array($this, 'unlockExit'));
}
register_shutdown_function(array($this, 'unlock'), $key);
$this->registerPid($lock_directory);
return $this->succeeded();
}
function lockDirectory($key)
{
return $this->createPath(
$this->options['lock_directory'], urlencode($key));
}
function mkdir($directory)
{
$parent = dirname($directory);
if ($parent === $directory) {
return true;
}
$this->mkdir(dirname($directory));
return @mkdir($directory);
}
function processExists($pid)
{
if ($this->loadExtension('posix')) {
return posix_kill($pid, 0);
} else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
return intval(exec(sprintf(
'tasklist /nh /fi "PID eq %s" 2>nul | find /C "%s"',
$pid, $pid)));
} else {
return intval(exec("ps -e|grep '^ *{$pid} '"));
}
}
function registerPid($directory)
{
$fp = fopen($this->createPath($directory, 'pid'), 'a');
if (!$fp) {
return false;
}
fwrite($fp, getmypid());
fclose($fp);
return true;
}
function succeeded()
{
return true;
}
function temporaryDirectory()
{
if (function_exists('sys_get_temp_dir')) {
return sys_get_temp_dir();
} else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
return $this->createPath('c:', 'temp');
} else {
return $this->createPath('', 'tmp');
}
}
function underscore($string)
{
return strtolower(preg_replace('/([A-Z])/', '_\1', $string));
}
function unlinkAll($file)
{
if (!is_dir($file)) {
return unlink($file);
}
$d = dir($file);
while ($entry = $d->read()) {
if ($entry === '.' || $entry === '..') {
continue;
}
$this->unlinkAll($this->createPath($d->path, $entry));
}
$d->close();
return rmdir($file);
}
function unlock($key)
{
if ($this->options['do_unlock']) {
return $this->unlinkAll($this->lockDirectory($key));
}
}
function unlockExit($signo)
{
$this->unlock($this->key);
exit;
}
function unlockIfInvalid($key)
{
$common_key = 'common';
// spin lock - failed if cannot locked in 2 sec
$common_lock = $this->lockDirectory($common_key);
for ($i = 0; $i < 200; ++$i) {
if ($this->mkdir($common_lock)) {
break;
}
usleep(10000);
}
if (!is_dir($common_lock)) {
$this->failed();
}
// critical section
if (!$this->isInvalidLock($this->lockDirectory($key))) {
$this->unlock($key);
}
// unlock
$this->unlock($common_key);
}
/*
* static methods
*/
function loadExtension($extension)
{
if (extension_loaded($extension)) {
return true;
}
if (defined('PHP_SHLIB_SUFFIX')) {
$suffix = PHP_SHLIB_SUFFIX;
} else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$suffix = 'dll';
} else {
$suffix = 'so';
}
$prefix = $suffix === 'dll' ? 'php_' : '';
$libraries = array("{$prefix}{$extension}.{$suffix}");
$libraries[] = "{$extension}.so";
$libraries[] = "php_{$extension}.dll";
$libraries = array_unique($libraries);
foreach ($libraries as $library) {
if (@dl($library)) {
return true;
}
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment