예제 #1
0
 public function testLockAndRelease()
 {
     $sm = new SharedMemory();
     $sm['test1'] = 'value1';
     $sm->lock();
     $this->assertEquals('value1', $sm['test1']);
     $sm['test2'] = $sm['test1'] . "+value2";
     $sm->release();
     $this->assertEquals('value1+value2', $sm['test2']);
 }
 public function Instance()
 {
     if (!isset(self::$mrInstance)) {
         self::$mrInstance = new SharedMemory();
     }
     return self::$mrInstance;
 }
 /**
  * Ensures that we can put objects of various types in shared memory and
  * retrieve them unchanged (between processes).
  */
 public function testInterProcessUsage()
 {
     $mem = new SharedMemory(self::$_mutex, SharedMemory::getRequiredBytes(array_values(self::$_testValues)));
     $bootstrapFile = realpath(__DIR__ . '/../classLoader.inc.php');
     $this->assertNotFalse($bootstrapFile);
     $cmd = 'env phpunit --no-configuration --bootstrap=' . $bootstrapFile . ' --filter=testPutValues ' . __FILE__ . ' > /dev/null';
     pclose(popen($cmd, 'r'));
     $this->_runTests($mem);
 }
 function Load($configFilename = '')
 {
     if (!class_exists('SharedMemory')) {
         require_once Configuration::Instance()->GetValue('application', 'gtfw_base') . 'main/lib/gtfw/shared_memory/SharedMemory.class.php';
     }
     if (SharedMemory::Instance()->VarIsSet($configFilename)) {
         $var_name = basename($configFilename, $this->mConfigFilenameBase);
         $res = array($var_name, SharedMemory::Instance()->Get($configFilename));
         return $res;
     } else {
         return array(false, false);
     }
 }
예제 #5
0
 /**
  * Determines information about the run environment and creates the shared
  * memory segment (an actual SysV shared memory segment on Unix, otherwise
  * a file).
  *
  * @param Mutex $mutex
  * @param int $segSize
  */
 public function __construct(Mutex $mutex, $segSize = null)
 {
     $this->_mutex = $mutex;
     if (self::$_useSysV === null) {
         self::$_useSysV = $this->_mutex->hasSysV();
         if (!self::$_useSysV) {
             self::$_shmFileBase = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'shm.{SEGMENT_KEY}.tmp';
             self::$_UNIT_SEPARATOR = chr(31);
             self::$_RECORD_SEPARATOR = chr(30);
         }
         self::$_activeShmResources = new SplQueue();
     }
     // We share the segment key with the mutex that governs access to it
     $this->_segmentKey = $this->_mutex->getLockID();
     if (!$segSize) {
         // Default to 10000 bytes
         $segSize = 10000;
     } else {
         /* Otherwise, allocate the extra space we'll need to store the
         			attached process count and variable count. Assume a three-digit
         			number of each (should be way more than enough). */
         $segSize += self::getRequiredBytes(array('100000'));
     }
     if (self::$_useSysV) {
         $this->_shmResource = shm_attach($this->_segmentKey, $segSize);
     } else {
         $this->_shmFile = str_replace('{SEGMENT_KEY}', $this->_segmentKey, self::$_shmFileBase);
         $this->_shmResource = fopen($this->_shmFile, 'a+b');
     }
     if (!$this->_shmResource) {
         throw new SharedMemoryException('Failed to obtain shared memory resource.');
     }
     /* Add the resource to the queue before the file name (if any); that
     		way if we need to clean up, we can iterate through the queue and know
     		that we will have closed any open file handles before deleting the
     		corresponding file. */
     self::$_activeShmResources->enqueue($this->_shmResource);
     if ($this->_shmFile) {
         self::$_activeShmResources->enqueue($this->_shmFile);
     }
     /* Keep track of the number of processes (or rather, the number of
     		SharedMemory instances across all processes) attached to this memory
     		segment so we can remove it when they all disappear. */
     /* This is somewhat of a misnomer; we're not counting processes, we are
     		counting instances across all processes. */
     $this->addToVar('_proccount', 1);
     if (!$this->hasVar('_varcount')) {
         $this->putVar('_varcount', 0);
     }
 }
예제 #6
0
 /**
  * Get any exceptions thrown by the threads.
  *
  * @return \Throwable[]
  */
 public function getExceptions() : array
 {
     return $this->memory->getExceptions();
 }
예제 #7
0
 /**
  * Handles certain setup tasks. This is the kind of thing that a
  * constructor would handle, but since this is an abstract class and I want
  * child classes to be free to accept any arguments they want, I'm not
  * using a constructor here.
  */
 private function _setupInstance()
 {
     if (!self::$_testedGenericSettings) {
         \PFXUtils::validateSettings(self::$_SETTINGS, self::$_SETTING_TESTS);
         self::_buildDefaultHTTPActionMap();
         self::$_validator = new \Validator();
     }
     /* If there is an exception type configured, validate that it really
     		exists. Otherwise default to RuntimeException. */
     if ($this->_EXCEPTION_TYPE) {
         if (!class_exists($this->_EXCEPTION_TYPE) || !is_a($this->_EXCEPTION_TYPE, 'Exception', true)) {
             throw new \Exception('Exception types registered in descendants of this ' . 'class must be valid Exception subclasses.');
         }
     } else {
         $this->_EXCEPTION_TYPE = 'RuntimeException';
     }
     if ($this->_responseFormat && array_key_exists($this->_responseFormat, self::$_STANDARD_PARSE_CALLBACKS)) {
         $callbackData = self::$_STANDARD_PARSE_CALLBACKS[$this->_responseFormat];
         $callback = array_shift($callbackData);
         $this->_registerParseCallback($callback, $callbackData);
     }
     self::$_validator->number($this->_responseTries, 'The number of attempts to use when connecting to API URLs ' . 'must be a non-zero integer.', \Validator::ASSERT_INT_DEFAULT);
     self::$_validator->number($this->_repeatPauseInterval, 'The number of seconds to wait before repeating an API ' . 'request must be a positive integer.', \Validator::ASSERT_INT | \Validator::ASSERT_POSITIVE);
     if ($this->_requestDelayInterval !== null) {
         self::$_validator->number($this->_requestDelayInterval, 'Delay intervals must be positive integers.', \Validator::ASSERT_INT | \Validator::ASSERT_POSITIVE);
         /* In order to observe this delay across processes, we need to have
         			a mutex and use shared memory. */
         try {
             if (!$this->_mutex) {
                 $this->_mutex = new \Mutex($this);
             }
             /* We will be keeping track of a millisecond timestamp, which
             			means 13 digits. */
             $allocBytes = \SharedMemory::getRequiredBytes(array(1000000000000));
             $this->_shmSegment = new \SharedMemory($this->_mutex, $allocBytes);
         } catch (\Exception $e) {
             throw new $this->_EXCEPTION_TYPE('Caught error while configuring shared memory segment.', null, $e);
         }
         /* Not only do we need to keep track of the delay interval, but we
         			also need a variable name that reflects the specific subclass for
         			which we are tracking this interval. */
         $this->_lastRequestTimeVarName = 'req' . get_class($this);
     }
     foreach (self::$_HTTP_RESPONSE_DEFAULT_MAP as $code => $action) {
         /* If the child has already registered certain actions in any of
         			these positions, skip them. */
         if (!array_key_exists($code, $this->_httpResponseActionMap)) {
             $this->_httpResponseActionMap[$code] = $action;
         }
     }
     $this->_instanceSetupComplete = true;
 }