5 Commits
0.1.1 ... 0.1.3

Author SHA1 Message Date
4652e464b9 Semaphores fully implemented 2018-04-15 20:48:22 +02:00
612cfc2035 Bugfixed SharedMemoryBlock, added tests 2018-04-15 20:31:35 +02:00
dcb059e4be Bugfixes
* Queue now has a destroy() method
* Examples updated
2018-04-15 18:50:19 +02:00
4e8ab73a88 Updated readme again 2018-04-15 18:39:10 +02:00
2652480c5d Updated readme 2018-04-15 18:27:51 +02:00
9 changed files with 224 additions and 24 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/vendor/
/composer.lock
/doc

138
README.md
View File

@ -2,26 +2,132 @@ noccylabs/ipc
=============
This is a one-size-fits-all IPC library to facilitate communication between
threads and processes. It contains the following features:
threads and processes.
**Core:**
For complete examples, see the `examples` directory in the source tree.
## Signals
- [ ] Semaphore
- [ ] Mutex
- [x] Queue
- [x] SharedMemory key-value store
- [ ] SharedMemory blocks
- [x] Signals
- [x] Locks
Asynchronous signals are automatically enabled if supported. Otherwise, the
`pcntl_signal_dispatch()` method must be frequently called from your main loop.
You can test for this using the `ASYNC_SIGNALS` constant:
**High-Level:**
if (!ASYNC_SIGNALS) {
pcntl_signal_dispatch();
}
- [ ] EventBridge
- [ ] EventDispatcher
- [ ] InterOp/Marshalling
- [x] Asynchronous timers
### Signal handlers
**Transports:**
Signal handlers allow for multiple listeners, with any one of them being able to
prevent the signal from bubbling up.
- [x] Stream channels
$handler = new SignalHandler(SIGUSR1);
$handler->addHandler(function () {
// Handle SIGUSR1, return true to stop bubbling
return true;
});
You can also handle as well as fire signals using the `Signal` class:
$signal = new Signal(SIGUSR1);
$signal->setHandler(function () {
// Handle SIGUSR1
});
// Dispatch the signal to ourselves
(new Signal(SIGUSR1))->dispatch($pid);
### Signal traps
Traps are used in the main loop to break on signals
$trap = new SignalTrap(SIGINT);
while (!$trap->isTrapped()) {
// ...
}
### Timers
Timers fire asynchronously at fixed 1 second intervals. It requires signals to be
processed; see above.
// Once every second...
$timer = new Timer(function () {
echo ".";
});
## File locks
File locks uses a shared file as a resource for locking.
// Creating the lock will not acquire it
$lock = new FileLock(__FILE__);
if (!$lock->acquire()) {
echo "fail!\n";
} else {
$lock->release();
}
## SysV wrappers
All these wrappers depend on a `KeyInterface` being passed to the constructor.
This is usually an instance of a `FileKey`, created as such:
$key = new FileKey(__FILE__);
The key has a project identifier that starts at `chr(0)`, or `"\0"`. To increase
this identifier, and thus point to another segment, just clone it.
$key2 = clone $key1;
### Semaphores
### Mutexes
### Message Queues
$key = new FileKey(__FILE__);
$msgq = new Queue($key);
$msgq->send(1, [ "Some data", [ "format"=>"foo" ]]);
$data = $msgq->receive(1, $type);
$msgq->destroy();
### Shared Memory
Shared memory using `SharedData` supports integrity checking when setting, using
the third parameter to `set()`.
$key = new FileKey(__FILE__);
$shm = new SharedData($key);
do {
$counter = $shm->get("counter") + 1;
} while (!$shm->set("counter", $counter, true));
$shm->destroy();
The `SharedMemory` class is a simple integer-indexed array
$key = new FileKey(__FILE__);
$shm = new SharedMemory($key);
$shm[0] = 42;
$shm->destroy();
## Communication
### Channels
Channels are essentially connected pipes. A channel can be created with a stream resource,
or through the `createPair()` factory method.
[ $ch1, $ch2 ] = StreamChannel::createPair();
$ch1->send($data);
$rcvd = $ch2->receive();

26
examples/queues.php Normal file
View File

@ -0,0 +1,26 @@
<?php
require_once __DIR__."/../vendor/autoload.php";
use NoccyLabs\Ipc\Key\FileKey;
use NoccyLabs\Ipc\Msg\Queue;
$key = new FileKey(__FILE__);
$msgq = new Queue($key);
// Send packages with msgtype >= 1...
$msgq->send(1, [ "what"=>"First" ]);
$msgq->send(2, [ "what"=>"Second" ]);
$msgq->send(3, [ "what"=>"Third" ]);
// Read messages by requesting a type...
$msg = $msgq->receive(2, $type);
printf("msg: %s, type: %d\n", json_encode($msg), $type);
// ...or read the first message with type 0...
$msg = $msgq->receive(0, $type);
printf("msg: %s, type: %d\n", json_encode($msg), $type);
$msg = $msgq->receive(0, $type);
printf("msg: %s, type: %d\n", json_encode($msg), $type);
$msgq->destroy();

View File

@ -32,3 +32,4 @@ if (!$shm->set("some.counter", $counter + 1, true)) {
echo "some.counter has been modified since last read\n";
}
$shm->destroy();

View File

@ -32,6 +32,13 @@ class Queue
}
public function destroy()
{
if ($this->resource) {
msg_remove_queue($this->resource);
}
}
/**
* Send to the queue
*

View File

@ -8,18 +8,25 @@ use NoccyLabs\Ipc\Key\KeyInterface;
class Semaphore
{
public function __construct(KeyInterface $key, int $max)
{
protected $resource;
public function __construct(KeyInterface $key, int $max, $perm = 0660, $autorelease = 1)
{
$this->resource = sem_get($key->getKey(), $max, $perm, $autorelease);
}
public function acquire(float $timeout)
public function destroy()
{
sem_remove($this->resource);
}
public function release()
public function acquire(float $timeout = 0):bool
{
return sem_acquire($this->resource, true);
}
public function release():bool
{
return sem_release($this->resource);
}
}

View File

@ -29,7 +29,7 @@ class SharedMemoryBlock
*/
public function __construct(KeyInterface $key, string $flags, int $memsize, int $perm = 0666)
{
if (!($shm_resource = shmop_open($key->getKey(), $memsize, $perm))) {
if (!($shm_resource = shmop_open($key->getKey(), $flags, $perm, $memsize))) {
throw new \RuntimeException("Unable to attach shm resource {$key}");
}

View File

@ -0,0 +1,27 @@
<?php
namespace NoccyLabs\Ipc\Sem;
use NoccyLabs\Ipc\Key\FileKey;
class SemaphoreTest extends \PhpUnit\Framework\TestCase
{
public function testCreatingAndAquiringSemaphore()
{
$key = new FileKey(__FILE__);
$sem = new Semaphore($key, 2);
$this->assertTrue($sem->acquire());
$this->assertTrue($sem->acquire());
$this->assertFalse($sem->acquire());
$this->assertTrue($sem->release());
$this->assertTrue($sem->acquire());
$this->assertFalse($sem->acquire());
$this->assertTrue($sem->release());
$this->assertTrue($sem->release());
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace NoccyLabs\Ipc\Shm;
use NoccyLabs\Ipc\Key\FileKey;
class SharedMemoryBlockTest extends \PhpUnit\Framework\TestCase
{
public function testWritingAndReading()
{
$key = new FileKey(__DIR__);
$shm = new SharedMemoryBlock($key, SharedMemoryBlock::FLAG_CREATE, 64);
$this->assertEquals(11, $shm->write("Hello World", 0));
$this->assertEquals("Hello World", $shm->read(11, 0));
$this->assertEquals(3, $shm->write("foo", 2));
$this->assertEquals("Hefoo World", $shm->read(11, 0));
$shm->destroy();
}
}