/** * This function wraps shmop_open with a Timer and an amount of tries to capture * shmop_open/release warnings which then would not provide further access to the * shared memory segment. * Additionally using synchronized threads would require PECL pthreads >= 2.0.0, * which we will not include to separate accesses from each other. * @param $key segment key passed onto shmop_open * @param $mode mode the segment should be opened with * @param $perms the permissions for the segment * @param $size the size of the segment * @param $tries number of tries to attach before throwing an exception * @param $timeout timeout in seconds for each try * @return shared memory segment id * @throws TimerException * @throws SegmentException * @bug 2016-00001 shmop_*, sem_* failures * @see Timer */ private function open($key = null, $mode = "w", $perms = 0600, $size = 1024, $timeout = 2, $tries = 3) { // set and start the timer $timer = null; if (strncmp(gettype($timeout), "integer", 7) == 0 && $timeout > 0) { $timer = new Timer($timeout); } // run the timer if ($timer !== null) { $timer->start(); } else { $this->log(__METHOD__ . ": %.", array(new TimerException("creation failed"))); throw new TimerException("creation failed"); } // then try to attach to the segment $sid = false; $try = 1; while ($timer !== null && $key !== null && $sid === false && $try <= $tries) { // try to create or attach to the segment $sid = @shmop_open($key, $mode, $perms, $size); if ($timer->get() === 0 && $timer->get_timed_out()) { $this->log(__METHOD__ . ": Attaching segment. Try #%. Timer timed out.", array($try)); $try++; $timer->start(); } } // throw some exceptions if something failed if ($sid === false) { $this->log(__METHOD__ . ": %", array(new SegmentException("creation/attaching failed", 5))); throw new SegmentException("creation/attaching failed", 5); } // otherwise return the shm segment id to access the segment return $sid; }
/** * Release a semaphore when th work is done. * DO NOT forget to call this when running sem_acquire without * $nowait flag set to true. * @throws TimerException * @throws SemaphoreException * @return true if the semaphore was release otherwise false */ public function release($timeout = 30, $tries = 3) { // set and start the timer $timer = null; if (strncmp(gettype($timeout), "integer", 7) == 0 && $timeout > 0) { $timer = new Timer($timeout); } if ($timer === null) { $this->log(__METHOD__ . ": %.", array(new TimerException("creation failed"))); throw new TimerException("creation failed"); } $timer->start(); // now try to acquire a semaphore $released = false; $try = 1; while (!is_null($this->semaphore->get_sem_res()) && $released === false && $timer !== null && $try <= $this->semaphore_max_try) { // use sem_acquire with $nowait flag to append a timer $released = @sem_release($this->semaphore->get_sem_res()); // retart the timer if ($timer->get() == 0 && $timer->get_timed_out()) { $this->log(__METHOD__ . ": Releasing. Try #%. Timer timed out.", array($try)); $try++; $timer->start(); } } // if releasing failed if ($released === false) { $this->log(__METHOD__ . ": %.", array(new SemaphoreException("release failed", 1))); throw new SemaphoreException("release failed", 1); } return $released; }
// the include path like 'Log.php' require_once "../../core/autoloader.class.php"; $al = new AutoLoader(false, "../.."); $al->expand(".test.class.php,.interface.php,.php"); $al->load(); // create a filelogger for this example $fl = new FileLogger("shmhandler.php"); $fl->logge("%", array($al)); $fl->logge("%", array($fl)); // use a timer to control an action $timeout = 2; $tries = 3; // set and start the timer $timer = null; if (strncmp(gettype($timeout), "integer", 7) == 0 && $timeout > 0) { $timer = new Timer($timeout); } if ($timer === null) { $fl->logge(__METHOD__ . ": %.", array(new TimerException("creation failed"))); throw new TimerException("creation failed"); } $timer->start(); // now try to acquire a semaphore $actiondone = false; $try = 1; while ($actiondone === false && $timer !== null && $try <= $tries) { // run an action $actiondone = false; // retart the timer if ($timer->get() == 0 && $timer->get_timed_out()) { $fl->logge(__METHOD__ . ": Try #%. Timer timed out.", array($try));