Common IPC facilities, including channels, locks, shared memory, and signals.
Go to file
2018-04-16 02:52:51 +02:00
examples Added multichannels and a simple channel-based bus 2018-04-16 02:52:51 +02:00
src Added multichannels and a simple channel-based bus 2018-04-16 02:52:51 +02:00
tests Added MultiStreamChannel to handle multiple endpoints 2018-04-16 01:54:30 +02:00
.gitignore Semaphores fully implemented 2018-04-15 20:48:22 +02:00
composer.json More examples and tweaks 2018-04-15 17:25:55 +02:00
phpunit.xml Initial commit 2018-04-15 16:51:42 +02:00
README.md Added multichannels and a simple channel-based bus 2018-04-16 02:52:51 +02:00

noccylabs/ipc

This is a one-size-fits-all IPC library to facilitate communication between threads and processes.

For complete examples, see the examples directory in the source tree.

Signals

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 SIGNALS_ASYNC constant:

if (!SIGNALS_ASYNC) {
    pcntl_signal_dispatch();
}

Signal handlers

Signal handlers allow for multiple listeners, with any one of them being able to prevent the signal from bubbling up.

$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

Semaphores are created with a key and a max count.

$key = new FileKey(__FILE__);
$sem = new Semaphore($key, 2);

$sem->allocate(); // -> true
$sem->allocate(); // -> true
$sem->allocate(); // -> false
$sem->release();

$mutex->destroy();

Mutexes

A mutex is a semaphore with a max count of 1.

$key = new FileKey(__FILE__);
$mutex = new Mutex($key);

$mutex->allocate(); // -> true
$mutex->allocate(); // -> false
$mutex->release();

$mutex->destroy();

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();

MultiChannels

The MultiStreamChannel lets you connect multiple clients to a single master channel.

$master = new MultiStreamChannel();

$ch1 = $master->createClient();
$ch2 = $master->createClient();
$ch1->send($data);
$rcvd = $ch2->receive();

Buses

Buses are high-level abstractions of channels, implementing limited rpc with handling of return values.

$master = new Master();

$client = $master->createClient();
$client->export("/db/updateindex", function ($schema) {
    // Update the index
    return true;
});

$other = $master->createClient();
$other->call("/db/updateindex", "*")->then(function ($status) {
    if ($status === true) {
        echo "Index updated!\n";
    }
});