diff --git a/classes/GPhpThread.html b/classes/GPhpThread.html new file mode 100644 index 0000000..bedc1a6 --- /dev/null +++ b/classes/GPhpThread.html @@ -0,0 +1,1674 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
+

GPhpThread - a heavy threads implementation in pure PHP - Documentation

+ + + + + +
+ +
+
+ + + + +
+
+ + +
+

+ GPhpThread + + +
+ in package + +
+ + +

+ +
+ + +
AbstractYes
+ +
+ + + +

A heavy thread creation and manipulation class.

+ +

Provides purely implemented in php instruments for "thread" creation +and manipulation. A shell access, pcntl, posix, linux OS and PHP 5.3+ +are required.

+
+ + + + + +

+ Table of Contents + + +

+ + + + + + + + + + +

+ Methods + + +

+
+
+ __construct() + +  : mixed +
+
Constructor.
+ +
+ __destruct() + +  : mixed +
+
Destructor (default). It will not be called in the heavy thread if thread exit codes are disabled!
+ +
+ BGN_HIGH_PRIOR_EXEC_BLOCK() + +  : void +
+
Marks the start of a code block with high execution priority.
+ +
+ END_HIGH_PRIOR_EXEC_BLOCK() + +  : void +
+
Marks the end of a code block with high execution priority.
+ +
+ getExitCode() + +  : int +
+
Returns the thread's exit code.
+ +
+ getPid() + +  : int|bool +
+
Returns the current thread's (process) id.
+ +
+ getPriority() + +  : int|bool +
+
Returns the current execution priority of the thread.
+ +
+ isAlive() + +  : bool +
+
Checks if the thread is alive.
+ +
+ isInGPhpThread() + +  : null|bool +
+
Execution protector. Recommended to be used everywhere where execution is not desired.
+ +
+ isParentAlive() + +  : bool +
+
Checks if the creator of the heavy thread is alive.
+ +
+ join() + +  : bool +
+
Waits for executing thread to return.
+ +
+ pause() + +  : bool +
+
Pauses the execution of the thread.
+ +
+ resetThreadIdGenerator() + +  : void +
+
Resets the internal thread id generator. This can be used to allow creation of threads from another thread.
+ +
+ resume() + +  : bool +
+
Resumes the execution of a paused thread.
+ +
+ run() + +  : void +
+
Abstract method, the entry point of a particular GPhpThread inheritor implementation.
+ +
+ setPriority() + +  : bool +
+
Sets the execution priority of the thread. A super user privileges are required.
+ +
+ start() + +  : bool +
+
Starts the thread.
+ +
+ stop() + +  : bool +
+
Stops executing thread.
+ +
+ makeNicer() + +  : bool +
+
At process level decreases the niceness of a heavy "thread" making its priority higher. Multiple calls of the method will accumulate and increase the effect.
+ +
+ makeUnfriendlier() + +  : bool +
+
At process level increases the niceness of a heavy "thread" making its priority lower. Multiple calls of the method will accumulate and increase the effect.
+ +
+ milliSleep() + +  : bool +
+
Suspends the thread execution for a specific amount of milliseconds, redirecting the CPU resources to somewhere else.
+ +
+ setExitCode() + +  : void +
+
Specifies the running thread's exit code when it terminates.
+ +
+ sleep() + +  : bool +
+
Suspends the thread execution for a specific amount of time, redirecting the CPU resources to somewhere else. The total delay is the sum of all passed parameters.
+ +
+ amIParent() + +  : bool +
+
Returns if the current process is a parent (has created thread).
+ +
+ notifyParentThatChildIsTerminated() + +  : void +
+
Notifies the parent of the current thread that the thread has exited.
+ +
+ + + + + + + + +
+

+ Methods + + +

+
+

+ __construct() + + +

+ + +

Constructor.

+ + + public + __construct(GPhpThreadCriticalSection|null &$criticalSection, bool $allowThreadExitCodes) : mixed + +
+
+ +
Parameters
+
+
+ $criticalSection + : GPhpThreadCriticalSection|null +
+
+

Instance of the critical section that is going to be associated with the created thread. Variable with null value is also valid. REFERENCE type.

+
+ +
+
+ $allowThreadExitCodes + : bool +
+
+

Activates the support of thread exit codes. In that case the programmer needs to make sure that before the creation of a heavy thread there are no initialized objects whose destructors and particularly their multiple execution (in all the children and once in the parent) will affect the execution of the program in an undefined way.

+
+ +
+
+ + + + +
+
+

+ __destruct() + + +

+ + +

Destructor (default). It will not be called in the heavy thread if thread exit codes are disabled!

+ + + public + __destruct() : mixed + +
+
+ + + + + +
+
+

+ BGN_HIGH_PRIOR_EXEC_BLOCK() + + +

+ + +

Marks the start of a code block with high execution priority.

+ + + public + final static BGN_HIGH_PRIOR_EXEC_BLOCK() : void + +
+
+ + + + + +
+
+

+ END_HIGH_PRIOR_EXEC_BLOCK() + + +

+ + +

Marks the end of a code block with high execution priority.

+ + + public + final static END_HIGH_PRIOR_EXEC_BLOCK() : void + +
+
+ + + + + +
+
+

+ getExitCode() + + +

+ + +

Returns the thread's exit code.

+ + + public + final getExitCode() : int + +
+
+ + + + +
+
Return values
+ int +
+ +
+
+

+ getPid() + + +

+ + +

Returns the current thread's (process) id.

+ + + public + getPid() : int|bool + +
+
+ + + + +
+
Return values
+ int|bool + — +

On success returns a number different than 0. Otherwise returns false.

+
+ +
+ +
+
+

+ getPriority() + + +

+ + +

Returns the current execution priority of the thread.

+ + + public + getPriority() : int|bool + +
+
+ + + + +
+
Return values
+ int|bool + — +

On success the priority number in the interval [-20; 20] where the lower value means higher priority. On failure returns false.

+
+ +
+ +
+
+

+ isAlive() + + +

+ + +

Checks if the thread is alive.

+ + + public + isAlive() : bool + +
+
+ + + + +
+
Return values
+ bool + — +

Returns true if the thread is alive otherwise returns false.

+
+ +
+ +
+
+

+ isInGPhpThread() + + +

+ + +

Execution protector. Recommended to be used everywhere where execution is not desired.

+ + + public + static isInGPhpThread(null|GPhpThreadNotCloneableContainer &$isInsideGPhpThread) : null|bool + +
+
+

For e.g. destructors which should be executed only in the master process. +Indicates whether the place from which this method is called is a heavy thread or not.

+

Can be used in 2 different ways. A direct way where the supplied parameter points to NULL. +In this case the result is immediately returned, but the user will not be able to ignore +the effect in any "inner" threads without using resetThreadIdGenerator() method which on the +other hand will affect any previously created object instances (before the thread was launched (forked)).

+

The other way is by subscribing a variable (most useful when is done in the constructor of your +affected class). When subscribed initially its value will be set to false, but it will be +updated after any calls to start()/stop().

+
+ +
Parameters
+
+
+ $isInsideGPhpThread + : null|GPhpThreadNotCloneableContainer +
+
+

A REFERENCE type. If it's set to null, the function will immediately return the result. Otherwise the variable will be subscribed for the result during the program's execution and its initial value will be set to false.

+
+ +
+
+ + +
+ Tags + + +
+
+
+ throws +
+
+ GPhpThreadException + +

If the supplied parameter is not of a GPhpThreadNotCloneableContainer or NULL type.

+
+ +
+
+ +
+
Return values
+ null|bool + — +

Null if a variable is subscribed for the result. Else if the method caller is part ot a heavy thread returns true otherwise false.

+
+ +
+ +
+
+

+ isParentAlive() + + +

+ + +

Checks if the creator of the heavy thread is alive.

+ + + public + isParentAlive() : bool + +
+
+ + + + +
+
Return values
+ bool + — +

Returns true if the parent is alive otherwise returns false.

+
+ +
+ +
+
+

+ join() + + +

+ + +

Waits for executing thread to return.

+ + + public + final join([bool $useBlocking = true ]) : bool + +
+
+ +
Parameters
+
+
+ $useBlocking + : bool + = true
+
+

If is set to true will block the until the thread returns.

+
+ +
+
+ + + +
+
Return values
+ bool + — +

True if the thread has joined otherwise false.

+
+ +
+ +
+
+

+ pause() + + +

+ + +

Pauses the execution of the thread.

+ + + public + final pause() : bool + +
+
+ + + + +
+
Return values
+ bool + — +

True if the pause request was successfully sent otherwise false.

+
+ +
+ +
+
+

+ resetThreadIdGenerator() + + +

+ + +

Resets the internal thread id generator. This can be used to allow creation of threads from another thread.

+ + + public + static resetThreadIdGenerator() : void + +
+
+

Not recommended to be used especially in a more complex cases.

+
+ + + + + +
+
+

+ resume() + + +

+ + +

Resumes the execution of a paused thread.

+ + + public + final resume() : bool + +
+
+ + + + +
+
Return values
+ bool + — +

True if the execution resume request was successfully sent otherwise false.

+
+ +
+ +
+
+

+ run() + + +

+ + +

Abstract method, the entry point of a particular GPhpThread inheritor implementation.

+ + + public + abstract run() : void + +
+
+ + + + + +
+
+

+ setPriority() + + +

+ + +

Sets the execution priority of the thread. A super user privileges are required.

+ + + public + setPriority(int $priority) : bool + +
+
+ +
Parameters
+
+
+ $priority + : int +
+
+

The priority number in the interval [-20; 20] where the lower value means higher priority.

+
+ +
+
+ + + +
+
Return values
+ bool + — +

Returns true on success otherwise returns false.

+
+ +
+ +
+
+

+ start() + + +

+ + +

Starts the thread.

+ + + public + final start() : bool + +
+
+ + + + +
+
Return values
+ bool + — +

On successful execution returns true otherwise returns false.

+
+ +
+ +
+
+

+ stop() + + +

+ + +

Stops executing thread.

+ + + public + final stop([bool $force = false ]) : bool + +
+
+ +
Parameters
+
+
+ $force + : bool + = false
+
+

If it is set to true if performs forced stop (termination).

+
+ +
+
+ + + +
+
Return values
+ bool + — +

True if the stop request was sent successfully otherwise false.

+
+ +
+ +
+
+

+ makeNicer() + + +

+ + +

At process level decreases the niceness of a heavy "thread" making its priority higher. Multiple calls of the method will accumulate and increase the effect.

+ + + protected + makeNicer() : bool + +
+
+ + + +
+ Tags + + +
+
+
+ see +
+
+ GPhpThread::makeUnfriendlier() + +

A method with the opposite effect is GPhpThread::makeUnfriendlier().

+
+ +
+
+ +
+
Return values
+ bool + — +

Returns true on success or false in case of error or lack of privileges.

+
+ +
+ +
+
+

+ makeUnfriendlier() + + +

+ + +

At process level increases the niceness of a heavy "thread" making its priority lower. Multiple calls of the method will accumulate and increase the effect.

+ + + protected + makeUnfriendlier() : bool + +
+
+ + + +
+ Tags + + +
+
+
+ see +
+
+ GPhpThread::makeNicer() + +

A method with the opposite effect is GPhpThread::makeNicer().

+
+ +
+
+ +
+
Return values
+ bool + — +

Returns true on success or false in case of error or lack of privileges.

+
+ +
+ +
+
+

+ milliSleep() + + +

+ + +

Suspends the thread execution for a specific amount of milliseconds, redirecting the CPU resources to somewhere else.

+ + + protected + milliSleep(int $milliseconds) : bool + +
+
+ +
Parameters
+
+
+ $milliseconds + : int +
+
+

The delay in milliseconds.

+
+ +
+
+ + +
+ Tags + + +
+
+
+ see +
+
+ GPhpThread::sleep() + +

Another similar method is sleep().

+
+ +
+
+ +
+
Return values
+ bool + — +

Returns true after all of the specified delay time elapsed. If the sleep was interrupted returns false.

+
+ +
+ +
+
+

+ setExitCode() + + +

+ + +

Specifies the running thread's exit code when it terminates.

+ + + protected + final setExitCode(int $exitCode) : void + +
+
+ +
Parameters
+
+
+ $exitCode + : int +
+
+

The exit code with which the thread will quit.

+
+ +
+
+ + + + +
+
+

+ sleep() + + +

+ + +

Suspends the thread execution for a specific amount of time, redirecting the CPU resources to somewhere else. The total delay is the sum of all passed parameters.

+ + + protected + sleep(int $microseconds[, int $seconds = 0 ]) : bool + +
+
+ +
Parameters
+
+
+ $microseconds + : int +
+
+

The delay in microseconds.

+
+ +
+
+ $seconds + : int + = 0
+
+

(optional) The delay in seconds.

+
+ +
+
+ + +
+ Tags + + +
+
+
+ see +
+
+ GPhpThread::milliSleep() + +

Another similar method is milliSleep().

+
+ +
+
+ +
+
Return values
+ bool + — +

Returns true after all of the specified delay time elapsed. If the sleep was interrupted returns false.

+
+ +
+ +
+
+

+ amIParent() + + +

+ + +

Returns if the current process is a parent (has created thread).

+ + + private + amIParent() : bool + +
+
+ + + + +
+
Return values
+ bool + — +

If it is a parent returns true otherwise returns false.

+
+ +
+ +
+
+

+ notifyParentThatChildIsTerminated() + + +

+ + +

Notifies the parent of the current thread that the thread has exited.

+ + + private + notifyParentThatChildIsTerminated() : void + +
+
+ + + + + +
+
+ +
+
+
+
+

+        
+ +
+
+ + + +
+
+
+ +
+ On this page + + +
+ +
+
+
+
+
+

Search results

+ +
+
+
    +
    +
    +
    +
    + + +
    + + + + + + + + diff --git a/classes/GPhpThreadCriticalSection.html b/classes/GPhpThreadCriticalSection.html new file mode 100644 index 0000000..d303a08 --- /dev/null +++ b/classes/GPhpThreadCriticalSection.html @@ -0,0 +1,2286 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
    +

    GPhpThread - a heavy threads implementation in pure PHP - Documentation

    + + + + + +
    + +
    +
    + + + + +
    +
    + + +
    +

    + GPhpThreadCriticalSection + + +
    + in package + +
    + + +

    + +
    + + +
    + + + +

    Critical section for sharing data between multiple processes.

    + +

    It provides a slower data-safe manipulating methods and unsafe faster methods.

    +
    + + +
    + Tags + + +
    +
    +
    + see +
    +
    + GPhpThreadIntercom + +

    \GPhpThreadIntercom is used for synchronization between the different processes.

    +
    + +
    +
    + + + +

    + Table of Contents + + +

    + + + + + + + + + + +

    + Methods + + +

    +
    +
    + __construct() + +  : mixed +
    +
    Constructor.
    + +
    + __destruct() + +  : mixed +
    +
    Destructor.
    + +
    + addOrUpdateResource() + +  : bool +
    +
    Adds or updates shared resource in a reliable, slower way. A lock of the critical section is required.
    + +
    + addOrUpdateUnrelResource() + +  : bool +
    +
    Adds or updates shared resource in an unreliable, faster way. A lock of the critical section is NOT required.
    + +
    + cleanPipeGarbage() + +  : int +
    +
    Cleans pipe files garbage left from any ungracefully terminated instances.
    + +
    + dispatch() + +  : void +
    +
    Dispatcher responsible for the thread intercommunication and communication with their parent process.
    + +
    + finalize() + +  : void +
    +
    Finalization of a thread instance that ended and soon will be destroyed.
    + +
    + getResourceNames() + +  : array<string|int, mixed> +
    +
    Returns the names of all reliable shared resources.
    + +
    + getResourceValue() + +  : mixed +
    +
    Returns an reliable resource value by asking the dispatcher for it. An ownership of the critical section is required.
    + +
    + getResourceValueFast() + +  : mixed +
    +
    Returns an reliable resource without trying to ask for it the dispatcher.
    + +
    + getUnrelResourceNames() + +  : array<string|int, mixed> +
    +
    Returns the names of all unreliable shared resources.
    + +
    + getUnrelResourceValue() + +  : mixed +
    +
    Returns an unreliable resource value by asking the dispatcher for it. An ownership of the critical section is required.
    + +
    + getUnrelResourceValueFast() + +  : mixed +
    +
    Returns an unreliable resource without trying to ask for it the dispatcher.
    + +
    + initialize() + +  : bool +
    +
    Initializes the critical section.
    + +
    + lock() + +  : bool +
    +
    Tries to lock the associated with the instance critical section.
    + +
    + removeResource() + +  : bool +
    +
    Removes shared resource in a reliable, slower way. A lock of the critical section is required.
    + +
    + removeUnrelResource() + +  : bool +
    +
    Removes shared resource in an unreliable, faster way. A lock of the critical section is NOT required.
    + +
    + unlock() + +  : bool +
    +
    Tries to unlock the associated with the instance critical section.
    + +
    + dataDispatch() + +  : void +
    +
    Operations on the transferred data dispatch helper.
    + +
    + decodeMessage() + +  : void +
    +
    Decodes encoded from GPhpThread's instance message.
    + +
    + doIOwnIt() + +  : bool +
    +
    Confirms if the current thread has the ownership of the critical section associated with it.
    + +
    + encodeMessage() + +  : string +
    +
    Encodes data in a message that will be sent to the thread process dispatcher.
    + +
    + isIntercomBroken() + +  : bool +
    +
    Checks if the internal intercom is broken.
    + +
    + isPidAlive() + +  : bool +
    +
    Checks if specific process id is still alive.
    + +
    + receive() + +  : bool +
    +
    Receives data operation from the main process dispatcher.
    + +
    + requestLock() + +  : bool +
    +
    Tries to lock the critical section.
    + +
    + requestUnlock() + +  : bool +
    +
    Tries to unlock the critical section.
    + +
    + send() + +  : bool +
    +
    Sends data operation to the main process dispatcher.
    + +
    + sortByLockAndDispatchPriority() + +  : int +
    +
    Sort by occurred lock and dispatch priority. This is a workaround +method required for PHP 5.3 and relies on an initialized +$bindVariable inside this class.
    + +
    + sortByLockDispatchPriorityAndMostThreadsInside() + +  : int +
    +
    Sort by occurred lock, dispatch priority and most threads using +the critical section. This is workaround method required for +PHP 5.3 and relies on an initialized $bindVariable inside this +class.
    + +
    + updateDataContainer() + +  : bool +
    +
    Executes data operation on the internal shared data container.
    + +
    + + + + + + + + +
    +

    + Methods + + +

    +
    +

    + __construct() + + +

    + + +

    Constructor.

    + + + public + __construct([string $pipeDirectory = '/dev/shm' ]) : mixed + +
    +
    + +
    Parameters
    +
    +
    + $pipeDirectory + : string + = '/dev/shm'
    +
    +

    The directory where the pipe files for the inter-process communication will be stored.

    +
    + +
    +
    + + + + +
    +
    +

    + __destruct() + + +

    + + +

    Destructor.

    + + + public + __destruct() : mixed + +
    +
    + + + + + +
    +
    +

    + addOrUpdateResource() + + +

    + + +

    Adds or updates shared resource in a reliable, slower way. A lock of the critical section is required.

    + + + public + addOrUpdateResource(string $name, mixed $value) : bool + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the resource.

    +
    + +
    +
    + $value + : mixed +
    +
    +

    The value of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise returns false.

    +
    + +
    + +
    +
    +

    + addOrUpdateUnrelResource() + + +

    + + +

    Adds or updates shared resource in an unreliable, faster way. A lock of the critical section is NOT required.

    + + + public + addOrUpdateUnrelResource(string $name, mixed $value) : bool + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the resource.

    +
    + +
    +
    + $value + : mixed +
    +
    +

    The value of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise returns false.

    +
    + +
    + +
    +
    +

    + cleanPipeGarbage() + + +

    + + +

    Cleans pipe files garbage left from any ungracefully terminated instances.

    + + + public + cleanPipeGarbage() : int + +
    +
    + + + + +
    +
    Return values
    + int + — +

    The total number of unused, cleaned pipe garbage files.

    +
    + +
    + +
    +
    +

    + dispatch() + + +

    + + +

    Dispatcher responsible for the thread intercommunication and communication with their parent process.

    + + + public + static dispatch([bool $useBlocking = false ]) : void + +
    +
    + +
    Parameters
    +
    +
    + $useBlocking + : bool + = false
    +
    +

    On true blocks the internal execution until communication data is available for the current dispatched thread otherwise it skips it.

    +
    + +
    +
    + + + + +
    +
    +

    + finalize() + + +

    + + +

    Finalization of a thread instance that ended and soon will be destroyed.

    + + + public + finalize(int $threadId) : void + +
    +
    + +
    Parameters
    +
    +
    + $threadId + : int +
    +
    +

    The internal thread identifier.

    +
    + +
    +
    + + + + +
    +
    +

    + getResourceNames() + + +

    + + +

    Returns the names of all reliable shared resources.

    + + + public + getResourceNames() : array<string|int, mixed> + +
    +
    + + + + +
    +
    Return values
    + array<string|int, mixed> + — +

    An array of (0 => 'resource name1', 1 => 'resource name2', ...)

    +
    + +
    + +
    +
    +

    + getResourceValue() + + +

    + + +

    Returns an reliable resource value by asking the dispatcher for it. An ownership of the critical section is required.

    + + + public + getResourceValue(string $name) : mixed + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the desired resource.

    +
    + +
    +
    + + +
    + Tags + + +
    +
    +
    + throws +
    +
    + GPhpThreadException + +

    If the critical section ownership is not obtained.

    +
    + +
    +
    + +
    +
    Return values
    + mixed + — +

    The resource value or null if the resource was not found.

    +
    + +
    + +
    +
    +

    + getResourceValueFast() + + +

    + + +

    Returns an reliable resource without trying to ask for it the dispatcher.

    + + + public + getResourceValueFast(string $name) : mixed + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + mixed + — +

    Returns the resource value or null on failure or if the resource name was not found.

    +
    + +
    + +
    +
    +

    + getUnrelResourceNames() + + +

    + + +

    Returns the names of all unreliable shared resources.

    + + + public + getUnrelResourceNames() : array<string|int, mixed> + +
    +
    + + + + +
    +
    Return values
    + array<string|int, mixed> + — +

    An array of (0 => 'resource name1', 1 => 'resource name2', ...)

    +
    + +
    + +
    +
    +

    + getUnrelResourceValue() + + +

    + + +

    Returns an unreliable resource value by asking the dispatcher for it. An ownership of the critical section is required.

    + + + public + getUnrelResourceValue(string $name) : mixed + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the desired resource.

    +
    + +
    +
    + + +
    + Tags + + +
    +
    +
    + throws +
    +
    + GPhpThreadException + +

    If the critical section ownership is not obtained.

    +
    + +
    +
    + +
    +
    Return values
    + mixed + — +

    The resource value or null if the resource was not found.

    +
    + +
    + +
    +
    +

    + getUnrelResourceValueFast() + + +

    + + +

    Returns an unreliable resource without trying to ask for it the dispatcher.

    + + + public + getUnrelResourceValueFast(string $name) : mixed + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + mixed + — +

    Returns the resource value or null on failure or if the resource name was not found.

    +
    + +
    + +
    +
    +

    + initialize() + + +

    + + +

    Initializes the critical section.

    + + + public + initialize(int $afterForkPid, int $threadId) : bool + +
    +
    + +
    Parameters
    +
    +
    + $afterForkPid + : int +
    +
    +

    The process identifier obtained after the execution of a fork() used to differentiate between different processes - pseudo threads.

    +
    + +
    +
    + $threadId + : int +
    +
    +

    The internal to the GPhpThread identifier of the current thread instance which is unique identifier in the context of the current process.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    On success returns true otherwise false.

    +
    + +
    + +
    +
    +

    + lock() + + +

    + + +

    Tries to lock the associated with the instance critical section.

    + + + public + lock([bool $useBlocking = true ]) : bool + +
    +
    + +
    Parameters
    +
    +
    + $useBlocking + : bool + = true
    +
    +

    If it's set to true the method will block until a lock is successfully established.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise returns false.

    +
    + +
    + +
    +
    +

    + removeResource() + + +

    + + +

    Removes shared resource in a reliable, slower way. A lock of the critical section is required.

    + + + public + removeResource(string $name) : bool + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise returns false.

    +
    + +
    + +
    +
    +

    + removeUnrelResource() + + +

    + + +

    Removes shared resource in an unreliable, faster way. A lock of the critical section is NOT required.

    + + + public + removeUnrelResource(string $name) : bool + +
    +
    + +
    Parameters
    +
    +
    + $name + : string +
    +
    +

    The name of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise returns false.

    +
    + +
    + +
    +
    +

    + unlock() + + +

    + + +

    Tries to unlock the associated with the instance critical section.

    + + + public + unlock([bool $useBlocking = false ]) : bool + +
    +
    + +
    Parameters
    +
    +
    + $useBlocking + : bool + = false
    +
    +

    If it's set to true the method will block until an unlock is successfully established.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise returns false.

    +
    + +
    + +
    +
    +

    + dataDispatch() + + +

    + + +

    Operations on the transferred data dispatch helper.

    + + + private + static dataDispatch(GPhpThreadCriticalSection &$inst, int $threadId) : void + +
    +
    + +
    Parameters
    +
    +
    + $inst + : GPhpThreadCriticalSection +
    +
    +

    The instance of the critical section to work with

    +
    + +
    +
    + $threadId + : int +
    +
    +

    The identifier of the thread whose critical section is currently dispatched.

    +
    + +
    +
    + + + + +
    +
    +

    + decodeMessage() + + +

    + + +

    Decodes encoded from GPhpThread's instance message.

    + + + private + decodeMessage(string $encodedMsg, string &$msg, int &$pid, string &$name, mixed &$value) : void + +
    +
    + +
    Parameters
    +
    +
    + $encodedMsg + : string +
    +
    +

    The encoded message

    +
    + +
    +
    + $msg + : string +
    +
    +

    The encoded message type identifier. REFERENCE type.

    +
    + +
    +
    + $pid + : int +
    +
    +

    The process id of the sender. REFERENCE type.

    +
    + +
    +
    + $name + : string +
    +
    +

    The variable name whose data was sent. REFERENCE type.

    +
    + +
    +
    + $value + : mixed +
    +
    +

    The variable data contained in the encoded message. REFERENCE type.

    +
    + +
    +
    + + + + +
    +
    +

    + doIOwnIt() + + +

    + + +

    Confirms if the current thread has the ownership of the critical section associated with it.

    + + + private + doIOwnIt() : bool + +
    +
    + + + + +
    +
    Return values
    + bool +
    + +
    +
    +

    + encodeMessage() + + +

    + + +

    Encodes data in a message that will be sent to the thread process dispatcher.

    + + + private + encodeMessage(string $msg, string $name, mixed $value) : string + +
    +
    + +
    Parameters
    +
    +
    + $msg + : string +
    +
    +

    The message type identifier.

    +
    + +
    +
    + $name + : string +
    +
    +

    The variable name whose data is going to be sent.

    +
    + +
    +
    + $value + : mixed +
    +
    +

    The current value of the desired for sending variable.

    +
    + +
    +
    + + + +
    +
    Return values
    + string + — +

    The composed message string

    +
    + +
    + +
    +
    +

    + isIntercomBroken() + + +

    + + +

    Checks if the internal intercom is broken.

    + + + private + isIntercomBroken() : bool + +
    +
    + + + + +
    +
    Return values
    + bool + — +

    Returns true if the intercom is broken otherwise returns false.

    +
    + +
    + +
    +
    +

    + isPidAlive() + + +

    + + +

    Checks if specific process id is still alive.

    + + + private + isPidAlive(int $pid) : bool + +
    +
    + +
    Parameters
    +
    +
    + $pid + : int +
    +
    +

    The process identifier.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true if the pid is alive otherwise returns false.

    +
    + +
    + +
    +
    +

    + receive() + + +

    + + +

    Receives data operation from the main process dispatcher.

    + + + private + receive(string &$message, int &$pid, string &$resourceName, mixed &$resourceValue[, int $timeInterval = 700 ]) : bool + +
    +
    + +
    Parameters
    +
    +
    + $message + : string +
    +
    +

    The operation type code. REFERENCE type.

    +
    + +
    +
    + $pid + : int +
    +
    +

    The process id of the sender "thread". REFERENCE type.

    +
    + +
    +
    + $resourceName + : string +
    +
    +

    The name of resource that is holding a particular data that will be "shared". REFERENCE type.

    +
    + +
    +
    + $resourceValue + : mixed +
    +
    +

    The value of the resource. REFERENCE type.

    +
    + +
    +
    + $timeInterval + : int + = 700
    +
    +

    Internal wait time interval in milliseconds between each data check.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise false.

    +
    + +
    + +
    +
    +

    + requestLock() + + +

    + + +

    Tries to lock the critical section.

    + + + private + requestLock() : bool + +
    +
    + + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise false.

    +
    + +
    + +
    +
    +

    + requestUnlock() + + +

    + + +

    Tries to unlock the critical section.

    + + + private + requestUnlock() : bool + +
    +
    + + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise false.

    +
    + +
    + +
    +
    +

    + send() + + +

    + + +

    Sends data operation to the main process dispatcher.

    + + + private + send(string $operation, string $resourceName, mixed $resourceValue) : bool + +
    +
    + +
    Parameters
    +
    +
    + $operation + : string +
    +
    +

    The operation type code.

    +
    + +
    +
    + $resourceName + : string +
    +
    +

    The name of resource that is holding a particular data that will be "shared".

    +
    + +
    +
    + $resourceValue + : mixed +
    +
    +

    The value of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise false.

    +
    + +
    + +
    +
    +

    + sortByLockAndDispatchPriority() + + +

    + + +

    Sort by occurred lock and dispatch priority. This is a workaround +method required for PHP 5.3 and relies on an initialized +$bindVariable inside this class.

    + + + private + sortByLockAndDispatchPriority(mixed $a, mixed $b) : int + +
    +
    + +
    Parameters
    +
    +
    + $a + : mixed +
    +
    +

    The first key to be taken into account.

    +
    + +
    +
    + $b + : mixed +
    +
    +

    The second key to be taken into account.

    +
    + +
    +
    + + + +
    +
    Return values
    + int + — +

    -1, 0 or 1 depending on which key is more preferable.

    +
    + +
    + +
    +
    +

    + sortByLockDispatchPriorityAndMostThreadsInside() + + +

    + + +

    Sort by occurred lock, dispatch priority and most threads using +the critical section. This is workaround method required for +PHP 5.3 and relies on an initialized $bindVariable inside this +class.

    + + + private + static sortByLockDispatchPriorityAndMostThreadsInside(mixed $a, mixed $b) : int + +
    +
    + +
    Parameters
    +
    +
    + $a + : mixed +
    +
    +

    The first key to be taken into account.

    +
    + +
    +
    + $b + : mixed +
    +
    +

    The second key to be taken into account.

    +
    + +
    +
    + + + +
    +
    Return values
    + int + — +

    -1, 0 or 1 depending on which key is more preferable.

    +
    + +
    + +
    +
    +

    + updateDataContainer() + + +

    + + +

    Executes data operation on the internal shared data container.

    + + + private + updateDataContainer(string $actionType, string $name, mixed $value) : bool + +
    +
    + +
    Parameters
    +
    +
    + $actionType + : string +
    +
    +

    The performed operation code.

    +
    + +
    +
    + $name + : string +
    +
    +

    The name of the resource.

    +
    + +
    +
    + $value + : mixed +
    +
    +

    The value of the resource.

    +
    + +
    +
    + + + +
    +
    Return values
    + bool + — +

    Returns true on success otherwise false.

    +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    
    +        
    + +
    +
    + + + +
    +
    +
    + +
    + On this page + + +
    + +
    +
    +
    +
    +
    +

    Search results

    + +
    +
    +
      +
      +
      +
      +
      + + +
      + + + + + + + + diff --git a/classes/GPhpThreadException.html b/classes/GPhpThreadException.html new file mode 100644 index 0000000..b60ff69 --- /dev/null +++ b/classes/GPhpThreadException.html @@ -0,0 +1,374 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
      +

      GPhpThread - a heavy threads implementation in pure PHP - Documentation

      + + + + + +
      + +
      +
      + + + + +
      +
      + + +
      +

      + GPhpThreadException + + + extends Exception + + +
      + in package + +
      + + +

      + +
      + + +
      + + + +

      Exception thrown by GPhpThreads components

      + + + + + + +

      + Table of Contents + + +

      + + + + + + + + + + +

      + Methods + + +

      +
      +
      + __construct() + +  : mixed +
      +
      Constructor.
      + +
      + + + + + + + + +
      +

      + Methods + + +

      +
      +

      + __construct() + + +

      + + +

      Constructor.

      + + + public + __construct(string $msg[, int $code = 0 ][, Exception $previous = NULL ]) : mixed + +
      +
      + +
      Parameters
      +
      +
      + $msg + : string +
      +
      +

      Exception message.

      +
      + +
      +
      + $code + : int + = 0
      +
      +

      Exception code number.

      +
      + +
      +
      + $previous + : Exception + = NULL
      +
      +

      The previous exception used for the exception chaining.

      +
      + +
      +
      + + + + +
      +
      + +
      +
      +
      +
      +
      
      +        
      + +
      +
      + + + +
      +
      +
      + +
      + On this page + + +
      + +
      +
      +
      +
      +
      +

      Search results

      + +
      +
      +
        +
        +
        +
        +
        + + +
        + + + + + + + + diff --git a/classes/GPhpThreadIntercom.html b/classes/GPhpThreadIntercom.html new file mode 100644 index 0000000..f3e9006 --- /dev/null +++ b/classes/GPhpThreadIntercom.html @@ -0,0 +1,735 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
        +

        GPhpThread - a heavy threads implementation in pure PHP - Documentation

        + + + + + +
        + +
        +
        + + + + +
        +
        + + +
        +

        + GPhpThreadIntercom + + +
        + in package + +
        + + +

        + +
        + + +
        + + + +

        Process intercommunication class.

        + +

        A pipe inter-process communication method is used, based on asynchronous or synchronous communication.

        +
        + + + + + +

        + Table of Contents + + +

        + + + + + + + + + + +

        + Methods + + +

        +
        +
        + __construct() + +  : mixed +
        +
        Constructor.
        + +
        + __destruct() + +  : mixed +
        +
        Destructor. May try automatically to delete the pipe file.
        + +
        + getAutoDeletionFlag() + +  : bool +
        +
        Returns the state of the option automatic deletion of the pipe file.
        + +
        + isInitialized() + +  : bool +
        +
        Checks if the intercom is initialized and ready for use.
        + +
        + isReceivingDataAvailable() + +  : mixed +
        +
        Checks if there is pending data for receiving.
        + +
        + receive() + +  : string|null +
        +
        Receives data from the intercom.
        + +
        + send() + +  : bool +
        +
        Sends data through the intercom.
        + +
        + setAutoDeletionFlag() + +  : void +
        +
        Sets the automatic deletion option for the pipe file during the destruction of current instance.
        + +
        + + + + + + + + +
        +

        + Methods + + +

        +
        +

        + __construct() + + +

        + + +

        Constructor.

        + + + public + __construct(string $filePath[, bool $isReadMode = true ][, bool $autoDeletion = false ]) : mixed + +
        +
        + +
        Parameters
        +
        +
        + $filePath + : string +
        +
        +

        The file that is going to store the pipe.

        +
        + +
        +
        + $isReadMode + : bool + = true
        +
        +

        Indicates if the param is going to be read only

        +
        + +
        +
        + $autoDeletion + : bool + = false
        +
        +

        If it is set during the destruction of the GPhpThreadIntercom instance the pipe file will be also removed.

        +
        + +
        +
        + + + + +
        +
        +

        + __destruct() + + +

        + + +

        Destructor. May try automatically to delete the pipe file.

        + + + public + __destruct() : mixed + +
        +
        + + + + + +
        +
        +

        + getAutoDeletionFlag() + + +

        + + +

        Returns the state of the option automatic deletion of the pipe file.

        + + + public + getAutoDeletionFlag() : bool + +
        +
        + + + + +
        +
        Return values
        + bool +
        + +
        +
        +

        + isInitialized() + + +

        + + +

        Checks if the intercom is initialized and ready for use.

        + + + public + isInitialized() : bool + +
        +
        + + + + +
        +
        Return values
        + bool +
        + +
        +
        +

        + isReceivingDataAvailable() + + +

        + + +

        Checks if there is pending data for receiving.

        + + + public + isReceivingDataAvailable() : mixed + +
        +
        + + + + +
        +
        Return values
        + mixed + — +

        Returns 0 or false if there is no data up to 15 ms after the method is called. Otherwise returns the number of contained stream resources (usually 1).

        +
        + +
        + +
        +
        +

        + receive() + + +

        + + +

        Receives data from the intercom.

        + + + public + receive([int $timeout = 700 ]) : string|null + +
        +
        + +
        Parameters
        +
        +
        + $timeout + : int + = 700
        +
        +

        The maximum time period in milliseconds during which to wait for data to arrive.

        +
        + +
        +
        + + + +
        +
        Return values
        + string|null + — +

        If there is no data up to 700 ms after the method is called it returns NULL otherwise returns the data string itself.

        +
        + +
        + +
        +
        +

        + send() + + +

        + + +

        Sends data through the intercom.

        + + + public + send(string $dataString, int $dataLength) : bool + +
        +
        + +
        Parameters
        +
        +
        + $dataString + : string +
        +
        +

        The data to be sent

        +
        + +
        +
        + $dataLength + : int +
        +
        +

        The length of the data

        +
        + +
        +
        + + + +
        +
        Return values
        + bool + — +

        On success returns true otherwise false is returned.

        +
        + +
        + +
        +
        +

        + setAutoDeletionFlag() + + +

        + + +

        Sets the automatic deletion option for the pipe file during the destruction of current instance.

        + + + public + setAutoDeletionFlag(bool $booleanValue) : void + +
        +
        + +
        Parameters
        +
        +
        + $booleanValue + : bool +
        +
        + +
        +
        + + + + +
        +
        + +
        +
        +
        +
        +
        
        +        
        + +
        +
        + + + +
        +
        +
        + +
        + On this page + + +
        + +
        +
        +
        +
        +
        +

        Search results

        + +
        +
        +
          +
          +
          +
          +
          + + +
          + + + + + + + + diff --git a/classes/GPhpThreadLockGuard.html b/classes/GPhpThreadLockGuard.html new file mode 100644 index 0000000..2313461 --- /dev/null +++ b/classes/GPhpThreadLockGuard.html @@ -0,0 +1,632 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
          +

          GPhpThread - a heavy threads implementation in pure PHP - Documentation

          + + + + + +
          + +
          +
          + + + + +
          +
          + + +
          +

          + GPhpThreadLockGuard + + +
          + in package + +
          + + + implements + Serializable + +

          + +
          + + +
          + + + +

          A wrapper providing RAII mechanism for locking and unlocking +purposes of a critical section objects and a similar ones.

          + + + +
          + Tags + + +
          +
          +
          + see +
          +
          + GPhpThreadCriticalSection + + +
          +
          + throws +
          +
          + GPhpThreadException + +

          When improperly passed/configured a critical section or clone attempts are made.

          +
          + +
          +
          + + + +

          + Table of Contents + + +

          + + + +

          + Interfaces + + +

          +
          +
          Serializable
          + + + + + + +

          + Properties + + +

          +
          +
          + $criticalSectionObj + +  : object +
          + +
          + $unlockMethod + +  : string +
          + +
          + $unlockMethodsParams + +  : string +
          + +
          + +

          + Methods + + +

          +
          +
          + __construct() + +  : mixed +
          +
          Constructor. Immediately locks the passed critical section.
          + +
          + __destruct() + +  : mixed +
          +
          Destructor. Immediately unlocks the passed critical section.
          + +
          + + + + + + + +
          +

          + Properties + + +

          +
          +

          + $criticalSectionObj + + + + +

          + + + + + private + object + $criticalSectionObj + = \NULL + + +

          The critical section that will be un/locked. REFERENCE type.

          +
          + + + +
          +
          +

          + $unlockMethod + + + + +

          + + + + + private + string + $unlockMethod + = 'unlock' + + +

          The unlock method name of the critical section that will be called during an unlock.

          +
          + + + +
          +
          +

          + $unlockMethodsParams + + + + +

          + + + + + private + string + $unlockMethodsParams + = array() + + +

          The parameters passed to the critical section's unlock method during an unlock.

          +
          + + + +
          +
          + +
          +

          + Methods + + +

          +
          +

          + __construct() + + +

          + + +

          Constructor. Immediately locks the passed critical section.

          + + + public + final __construct(object &$criticalSectionObj[, string $lockMethod = 'lock' ][, array<string|int, mixed> $lockMethodParams = array() ][, string $unlockMethod = 'unlock' ][, array<string|int, mixed> $unlockMethodsParams = array() ]) : mixed + +
          +
          + +
          Parameters
          +
          +
          + $criticalSectionObj + : object +
          +
          +

          An initialized critical section object or similar. A REFERENCE type.

          +
          + +
          +
          + $lockMethod + : string + = 'lock'
          +
          +

          The name of the $criticalSectionObj's lock method that will be called.

          +
          + +
          +
          + $lockMethodParams + : array<string|int, mixed> + = array()
          +
          +

          Parameter that will be passed to the lock method of $criticalSectionObj.

          +
          + +
          +
          + $unlockMethod + : string + = 'unlock'
          +
          +

          The name of the $criticalSectionObj's unlock method that will be called.

          +
          + +
          +
          + $unlockMethodsParams + : array<string|int, mixed> + = array()
          +
          +

          Parameter that will be passed to the unlock method of $criticalSectionObj.

          +
          + +
          +
          + + +
          + Tags + + +
          +
          +
          + throws +
          +
          + GPhpThreadException + +

          Exception is thrown in case an uninitialized critical section is passed or the specified lock or unlock methods are missing.

          +
          + +
          +
          + + +
          +
          +

          + __destruct() + + +

          + + +

          Destructor. Immediately unlocks the passed critical section.

          + + + public + final __destruct() : mixed + +
          +
          + + + + + +
          +
          + +
          +
          +
          +
          +
          
          +        
          + +
          +
          + + + +
          +
          +
          + +
          + On this page + + +
          + +
          +
          +
          +
          +
          +

          Search results

          + +
          +
          +
            +
            +
            +
            +
            + + +
            + + + + + + + + diff --git a/classes/GPhpThreadNotCloneableContainer.html b/classes/GPhpThreadNotCloneableContainer.html new file mode 100644 index 0000000..7d6479b --- /dev/null +++ b/classes/GPhpThreadNotCloneableContainer.html @@ -0,0 +1,604 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
            +

            GPhpThread - a heavy threads implementation in pure PHP - Documentation

            + + + + + +
            + +
            +
            + + + + +
            +
            + + +
            +

            + GPhpThreadNotCloneableContainer + + +
            + in package + +
            + + + implements + Serializable + +

            + +
            + +
            FinalYes
            + + +
            + + + +

            A data container not allowed to be cloned.

            + +

            Once created, only REFERENCEs to it are allowed. +It is NOT protected against fork or direct import()/export(). If that is desired it should be wrapped.

            +
            + + +
            + Tags + + +
            +
            +
            + throws +
            +
            + GPhpThreadException + +

            When caught clone attempts.

            +
            + +
            +
            + + + +

            + Table of Contents + + +

            + + + +

            + Interfaces + + +

            +
            +
            Serializable
            + + + + + + +

            + Properties + + +

            +
            +
            + $variable + +  : mixed +
            + +
            + +

            + Methods + + +

            +
            +
            + __construct() + +  : mixed +
            +
            Constructor.
            + +
            + __toString() + +  : string +
            +
            Generates object id.
            + +
            + export() + +  : mixed +
            +
            Returns the contained value.
            + +
            + import() + +  : void +
            +
            Sets the value desired to be held.
            + +
            + + + + + + + +
            +

            + Properties + + +

            +
            +

            + $variable + + + + +

            + + + + + private + mixed + $variable + + + +

            The container holding the user's value

            +
            + + + +
            +
            + +
            +

            + Methods + + +

            +
            +

            + __construct() + + +

            + + +

            Constructor.

            + + + public + __construct() : mixed + +
            +
            + + + + + +
            +
            +

            + __toString() + + +

            + + +

            Generates object id.

            + + + public + final __toString() : string + +
            +
            + + + + +
            +
            Return values
            + string + — +

            The id of the current instance.

            +
            + +
            + +
            +
            +

            + export() + + +

            + + +

            Returns the contained value.

            + + + public + export() : mixed + +
            +
            + + + + +
            +
            Return values
            + mixed + — +

            The contained value.

            +
            + +
            + +
            +
            +

            + import() + + +

            + + +

            Sets the value desired to be held.

            + + + public + import(mixed $value) : void + +
            +
            + +
            Parameters
            +
            +
            + $value + : mixed +
            +
            +

            The value to be held inside this container.

            +
            + +
            +
            + + +
            + Tags + + +
            +
            +
            + throws +
            +
            + GPhpThreadException + +

            If an instance of \GPhpThreadNotCloneableContainer is passed.

            +
            + +
            +
            + + +
            +
            + +
            +
            +
            +
            +
            
            +        
            + +
            +
            + + + +
            +
            +
            + +
            + On this page + + +
            + +
            +
            +
            +
            +
            +

            Search results

            + +
            +
            +
              +
              +
              +
              +
              + + +
              + + + + + + + + diff --git a/css/base.css b/css/base.css new file mode 100644 index 0000000..3482dfb --- /dev/null +++ b/css/base.css @@ -0,0 +1,1231 @@ + + +:root { + /* Typography */ + --font-primary: 'Open Sans', Helvetica, Arial, sans-serif; + --font-secondary: 'Open Sans', Helvetica, Arial, sans-serif; + --font-monospace: 'Source Code Pro', monospace; + --line-height--primary: 1.6; + --letter-spacing--primary: .05rem; + --text-base-size: 1em; + --text-scale-ratio: 1.2; + + --text-xxs: calc(var(--text-base-size) / var(--text-scale-ratio) / var(--text-scale-ratio) / var(--text-scale-ratio)); + --text-xs: calc(var(--text-base-size) / var(--text-scale-ratio) / var(--text-scale-ratio)); + --text-sm: calc(var(--text-base-size) / var(--text-scale-ratio)); + --text-md: var(--text-base-size); + --text-lg: calc(var(--text-base-size) * var(--text-scale-ratio)); + --text-xl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + + --color-hue-red: 4; + --color-hue-pink: 340; + --color-hue-purple: 291; + --color-hue-deep-purple: 262; + --color-hue-indigo: 231; + --color-hue-blue: 207; + --color-hue-light-blue: 199; + --color-hue-cyan: 187; + --color-hue-teal: 174; + --color-hue-green: 122; + --color-hue-phpdocumentor-green: 96; + --color-hue-light-green: 88; + --color-hue-lime: 66; + --color-hue-yellow: 54; + --color-hue-amber: 45; + --color-hue-orange: 36; + --color-hue-deep-orange: 14; + --color-hue-brown: 16; + + /* Colors */ + --primary-color-hue: var(--color-hue-phpdocumentor-green, --color-hue-phpdocumentor-green); + --primary-color-saturation: 57%; + --primary-color: hsl(var(--primary-color-hue), var(--primary-color-saturation), 60%); + --primary-color-darken: hsl(var(--primary-color-hue), var(--primary-color-saturation), 40%); + --primary-color-darker: hsl(var(--primary-color-hue), var(--primary-color-saturation), 25%); + --primary-color-darkest: hsl(var(--primary-color-hue), var(--primary-color-saturation), 10%); + --primary-color-lighten: hsl(var(--primary-color-hue), calc(var(--primary-color-saturation) - 20%), 85%); + --primary-color-lighter: hsl(var(--primary-color-hue), calc(var(--primary-color-saturation) - 45%), 97.5%); + --dark-gray: #d1d1d1; + --light-gray: #f0f0f0; + + --text-color: var(--primary-color-darkest); + + --header-height: var(--spacing-xxxxl); + --header-bg-color: var(--primary-color); + --code-background-color: var(--primary-color-lighter); + --code-border-color: --primary-color-lighten; + --button-border-color: var(--primary-color-darken); + --button-color: transparent; + --button-color-primary: var(--primary-color); + --button-text-color: #555; + --button-text-color-primary: white; + --popover-background-color: rgba(255, 255, 255, 0.75); + --link-color-primary: var(--primary-color-darker); + --link-hover-color-primary: var(--primary-color-darkest); + --form-field-border-color: var(--dark-gray); + --form-field-color: #fff; + --admonition-success-color: var(--primary-color); + --admonition-border-color: silver; + --table-separator-color: var(--primary-color-lighten); + --title-text-color: var(--primary-color); + + --sidebar-border-color: var(--primary-color-lighten); + + /* Grid */ + --container-width: 1400px; + + /* Spacing */ + --spacing-base-size: 1rem; + --spacing-scale-ratio: 1.5; + + --spacing-xxxs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-xxs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-xs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-sm: calc(var(--spacing-base-size) / var(--spacing-scale-ratio)); + --spacing-md: var(--spacing-base-size); + --spacing-lg: calc(var(--spacing-base-size) * var(--spacing-scale-ratio)); + --spacing-xl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxxxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + + --border-radius-base-size: 3px; +} + +/* Base Styles +-------------------------------------------------- */ +body { + color: var(--text-color); + font-family: var(--font-primary); + font-size: var(--text-md); + letter-spacing: var(--letter-spacing--primary); + line-height: var(--line-height--primary); + width: 100%; +} + +.phpdocumentor h1, +.phpdocumentor h2, +.phpdocumentor h3, +.phpdocumentor h4, +.phpdocumentor h5, +.phpdocumentor h6 { + margin-bottom: var(--spacing-lg); + margin-top: var(--spacing-lg); + font-weight: 600; +} + +.phpdocumentor h1 { + font-size: var(--text-xxxxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.2; + margin-top: 0; +} + +.phpdocumentor h2 { + font-size: var(--text-xxxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.25; +} + +.phpdocumentor h3 { + font-size: var(--text-xxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.3; +} + +.phpdocumentor h4 { + font-size: var(--text-xl); + letter-spacing: calc(var(--letter-spacing--primary) / 2); + line-height: 1.35; + margin-bottom: var(--spacing-md); +} + +.phpdocumentor h5 { + font-size: var(--text-lg); + letter-spacing: calc(var(--letter-spacing--primary) / 4); + line-height: 1.5; + margin-bottom: var(--spacing-md); + margin-top: var(--spacing-md); +} + +.phpdocumentor h6 { + font-size: var(--text-md); + letter-spacing: 0; + line-height: var(--line-height--primary); + margin-bottom: var(--spacing-md); + margin-top: var(--spacing-md); +} +.phpdocumentor h1 .headerlink, +.phpdocumentor h2 .headerlink, +.phpdocumentor h3 .headerlink, +.phpdocumentor h4 .headerlink, +.phpdocumentor h5 .headerlink, +.phpdocumentor h6 .headerlink +{ + display: none; +} + +@media (min-width: 550px) { + .phpdocumentor h1 .headerlink, + .phpdocumentor h2 .headerlink, + .phpdocumentor h3 .headerlink, + .phpdocumentor h4 .headerlink, + .phpdocumentor h5 .headerlink, + .phpdocumentor h6 .headerlink { + display: inline; + transition: all .3s ease-in-out; + opacity: 0; + text-decoration: none; + color: silver; + font-size: 80%; + } + + .phpdocumentor h1:hover .headerlink, + .phpdocumentor h2:hover .headerlink, + .phpdocumentor h3:hover .headerlink, + .phpdocumentor h4:hover .headerlink, + .phpdocumentor h5:hover .headerlink, + .phpdocumentor h6:hover .headerlink { + opacity: 1; + } +} +.phpdocumentor p { + margin-top: 0; + margin-bottom: var(--spacing-md); +} +.phpdocumentor figure { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor figcaption { + text-align: center; + font-style: italic; + font-size: 80%; +} + +.phpdocumentor-uml-diagram svg { + max-width: 100%; + height: auto !important; +} +.phpdocumentor-line { + border-top: 1px solid #E1E1E1; + border-width: 0; + margin-bottom: var(--spacing-xxl); + margin-top: var(--spacing-xxl); +} +.phpdocumentor-section { + box-sizing: border-box; + margin: 0 auto; + max-width: var(--container-width); + padding: 0 var(--spacing-sm); + position: relative; + width: 100%; +} + +@media (min-width: 550px) { + .phpdocumentor-section { + padding: 0 var(--spacing-lg); + } +} + +@media (min-width: 1200px) { + .phpdocumentor-section { + padding: 0; + width: 95%; + } +} +.phpdocumentor-column { + box-sizing: border-box; + float: left; + width: 100%; +} + +@media (min-width: 550px) { + .phpdocumentor-column { + margin-left: 4%; + } + + .phpdocumentor-column:first-child { + margin-left: 0; + } + + .-one.phpdocumentor-column { + width: 4.66666666667%; + } + + .-two.phpdocumentor-column { + width: 13.3333333333%; + } + + .-three.phpdocumentor-column { + width: 22%; + } + + .-four.phpdocumentor-column { + width: 30.6666666667%; + } + + .-five.phpdocumentor-column { + width: 39.3333333333%; + } + + .-six.phpdocumentor-column { + width: 48%; + } + + .-seven.phpdocumentor-column { + width: 56.6666666667%; + } + + .-eight.phpdocumentor-column { + width: 65.3333333333%; + } + + .-nine.phpdocumentor-column { + width: 74.0%; + } + + .-ten.phpdocumentor-column { + width: 82.6666666667%; + } + + .-eleven.phpdocumentor-column { + width: 91.3333333333%; + } + + .-twelve.phpdocumentor-column { + margin-left: 0; + width: 100%; + } + + .-one-third.phpdocumentor-column { + width: 30.6666666667%; + } + + .-two-thirds.phpdocumentor-column { + width: 65.3333333333%; + } + + .-one-half.phpdocumentor-column { + width: 48%; + } + + /* Offsets */ + .-offset-by-one.phpdocumentor-column { + margin-left: 8.66666666667%; + } + + .-offset-by-two.phpdocumentor-column { + margin-left: 17.3333333333%; + } + + .-offset-by-three.phpdocumentor-column { + margin-left: 26%; + } + + .-offset-by-four.phpdocumentor-column { + margin-left: 34.6666666667%; + } + + .-offset-by-five.phpdocumentor-column { + margin-left: 43.3333333333%; + } + + .-offset-by-six.phpdocumentor-column { + margin-left: 52%; + } + + .-offset-by-seven.phpdocumentor-column { + margin-left: 60.6666666667%; + } + + .-offset-by-eight.phpdocumentor-column { + margin-left: 69.3333333333%; + } + + .-offset-by-nine.phpdocumentor-column { + margin-left: 78.0%; + } + + .-offset-by-ten.phpdocumentor-column { + margin-left: 86.6666666667%; + } + + .-offset-by-eleven.phpdocumentor-column { + margin-left: 95.3333333333%; + } + + .-offset-by-one-third.phpdocumentor-column { + margin-left: 34.6666666667%; + } + + .-offset-by-two-thirds.phpdocumentor-column { + margin-left: 69.3333333333%; + } + + .-offset-by-one-half.phpdocumentor-column { + margin-left: 52%; + } +} +.phpdocumentor a { + color: var(--link-color-primary); +} + +.phpdocumentor a:hover { + color: var(--link-hover-color-primary); +} +.phpdocumentor-button { + background-color: var(--button-color); + border: 1px solid var(--button-border-color); + border-radius: var(--border-radius-base-size); + box-sizing: border-box; + color: var(--button-text-color); + cursor: pointer; + display: inline-block; + font-size: var(--text-sm); + font-weight: 600; + height: 38px; + letter-spacing: .1rem; + line-height: 38px; + padding: 0 var(--spacing-xxl); + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-button .-wide { + width: 100%; +} + +.phpdocumentor-button:hover, +.phpdocumentor-button:focus { + border-color: #888; + color: #333; + outline: 0; +} + +.phpdocumentor-button.-primary { + background-color: var(--button-color-primary); + border-color: var(--button-color-primary); + color: var(--button-text-color-primary); +} + +.phpdocumentor-button.-primary:hover, +.phpdocumentor-button.-primary:focus { + background-color: var(--link-color-primary); + border-color: var(--link-color-primary); + color: var(--button-text-color-primary); +} +.phpdocumentor form { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-field { + background-color: var(--form-field-color); + border: 1px solid var(--form-field-border-color); + border-radius: var(--border-radius-base-size); + box-shadow: none; + box-sizing: border-box; + height: 38px; + padding: var(--spacing-xxxs) var(--spacing-xxs); /* The 6px vertically centers text on FF, ignored by Webkit */ + margin-bottom: var(--spacing-md); +} + +/* Removes awkward default styles on some inputs for iOS */ +input[type="email"], +input[type="number"], +input[type="search"], +input[type="text"], +input[type="tel"], +input[type="url"], +input[type="password"], +textarea { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; +} + +.phpdocumentor-textarea { + min-height: 65px; + padding-bottom: var(--spacing-xxxs); + padding-top: var(--spacing-xxxs); +} + +.phpdocumentor-field:focus { + border: 1px solid var(--button-color-primary); + outline: 0; +} + +label.phpdocumentor-label { + display: block; + margin-bottom: var(--spacing-xs); +} + +.phpdocumentor-fieldset { + border-width: 0; + padding: 0; +} + +input[type="checkbox"].phpdocumentor-field, +input[type="radio"].phpdocumentor-field { + display: inline; +} +.phpdocumentor-column ul, +div.phpdocumentor-list > ul, +ul.phpdocumentor-list { + list-style: circle; +} + +.phpdocumentor-column ol, +div.phpdocumentor-list > ol, +ol.phpdocumentor-list { + list-style: decimal; +} + + +.phpdocumentor-column ul, +div.phpdocumentor-list > ul, +ol.phpdocumentor-list, +ul.phpdocumentor-list { + margin-top: 0; + padding-left: var(--spacing-md); + margin-bottom: var(--spacing-sm); +} + +.phpdocumentor-column ul.-clean, +div.phpdocumentor-list > ul.-clean, +ul.phpdocumentor-list.-clean { + list-style: none; + padding-left: 0; +} + +dl { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-column ul ul, +div.phpdocumentor-list > ul ul, +ul.phpdocumentor-list ul.phpdocumentor-list, +ul.phpdocumentor-list ol.phpdocumentor-list, +ol.phpdocumentor-list ol.phpdocumentor-list, +ol.phpdocumentor-list ul.phpdocumentor-list { + font-size: var(--text-sm); + margin: 0 0 0 calc(var(--spacing-xs) * 2); +} + +.phpdocumentor-column ul li, +.phpdocumentor-list li { + padding-bottom: var(--spacing-xs); +} + +.phpdocumentor dl dt { + margin-bottom: var(--spacing-xs); +} + +.phpdocumentor dl dd { + margin-bottom: var(--spacing-md); +} +.phpdocumentor pre { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-code { + font-family: var(--font-monospace); + background: var(--code-background-color); + border: 1px solid var(--code-border-color); + border-radius: var(--border-radius-base-size); + font-size: var(--text-sm); + padding: var(--spacing-sm) var(--spacing-md); + width: 100%; + box-sizing: border-box; +} + +.phpdocumentor-code.-dark { + background: var(--primary-color-darkest); + color: var(--light-gray); + box-shadow: 0 2px 3px var(--dark-gray); +} + +pre > .phpdocumentor-code { + display: block; + white-space: pre; +} +.phpdocumentor blockquote { + border-left: 4px solid var(--primary-color-darken); + margin: var(--spacing-md) 0; + padding: var(--spacing-xs) var(--spacing-sm); + color: var(--primary-color-darker); + font-style: italic; +} + +.phpdocumentor blockquote p:last-of-type { + margin-bottom: 0; +} +.phpdocumentor table { + margin-bottom: var(--spacing-md); +} + +th.phpdocumentor-heading, +td.phpdocumentor-cell { + border-bottom: 1px solid var(--table-separator-color); + padding: var(--spacing-sm) var(--spacing-md); + text-align: left; +} + +th.phpdocumentor-heading:first-child, +td.phpdocumentor-cell:first-child { + padding-left: 0; +} + +th.phpdocumentor-heading:last-child, +td.phpdocumentor-cell:last-child { + padding-right: 0; +} +.phpdocumentor-label-line { + display: flex; + flex-direction: row; + gap: 1rem +} + +.phpdocumentor-label { + background: #f6f6f6; + border-radius: .25rem; + font-size: 80%; + display: inline-block; + overflow: hidden +} + +/* +It would be better if the phpdocumentor-element class were to become a flex element with a gap, but for #3337 that +is too big a fix and needs to be done in a new design iteration. +*/ +.phpdocumentor-signature + .phpdocumentor-label-line .phpdocumentor-label { + margin-top: var(--spacing-sm); +} + +.phpdocumentor-label span { + display: inline-block; + padding: .125rem .5rem; +} + +.phpdocumentor-label--success span:last-of-type { + background: #abe1ab; +} + +.phpdocumentor-header { + display: flex; + flex-direction: row; + align-items: stretch; + flex-wrap: wrap; + justify-content: space-between; + height: auto; + padding: var(--spacing-md) var(--spacing-md); +} + +.phpdocumentor-header__menu-button { + position: absolute; + top: -100%; + left: -100%; +} + +.phpdocumentor-header__menu-icon { + font-size: 2rem; + color: var(--primary-color); +} + +.phpdocumentor-header__menu-button:checked ~ .phpdocumentor-topnav { + max-height: 250px; + padding-top: var(--spacing-md); +} + +@media (min-width: 1000px) { + .phpdocumentor-header { + flex-direction: row; + padding: var(--spacing-lg) var(--spacing-lg); + min-height: var(--header-height); + } + + .phpdocumentor-header__menu-icon { + display: none; + } +} + +@media (min-width: 1000px) { + .phpdocumentor-header { + padding-top: 0; + padding-bottom: 0; + } +} +@media (min-width: 1200px) { + .phpdocumentor-header { + padding: 0; + } +} +.phpdocumentor-title { + box-sizing: border-box; + color: var(--title-text-color); + font-size: var(--text-xxl); + letter-spacing: .05rem; + font-weight: normal; + width: auto; + margin: 0; + display: flex; + align-items: center; +} + +.phpdocumentor-title.-without-divider { + border: none; +} + +.phpdocumentor-title__link { + transition: all .3s ease-out; + display: flex; + color: var(--title-text-color); + text-decoration: none; + font-weight: normal; + white-space: nowrap; + transform: scale(.75); + transform-origin: left; +} + +.phpdocumentor-title__link:hover { + transform: perspective(15rem) translateX(.5rem); + font-weight: 600; +} + +@media (min-width: 1000px) { + .phpdocumentor-title { + width: 22%; + border-right: var(--sidebar-border-color) solid 1px; + } + + .phpdocumentor-title__link { + transform-origin: left; + } +} + +@media (min-width: 1000px) { + .phpdocumentor-title__link { + transform: scale(.85); + } +} + +@media (min-width: 1200px) { + .phpdocumentor-title__link { + transform: scale(1); + } +} +.phpdocumentor-topnav { + display: flex; + align-items: center; + margin: 0; + max-height: 0; + overflow: hidden; + transition: max-height 0.2s ease-out; + flex-basis: 100%; +} + +.phpdocumentor-topnav__menu { + text-align: right; + list-style: none; + margin: 0; + padding: 0; + flex: 1; + display: flex; + flex-flow: row wrap; + justify-content: center; +} + +.phpdocumentor-topnav__menu-item { + margin: 0; + width: 100%; + display: inline-block; + text-align: center; + padding: var(--spacing-sm) 0 +} + +.phpdocumentor-topnav__menu-item.-social { + width: auto; + padding: var(--spacing-sm) +} + +.phpdocumentor-topnav__menu-item a { + display: inline-block; + color: var(--text-color); + text-decoration: none; + font-size: var(--text-lg); + transition: all .3s ease-out; + border-bottom: 1px dotted transparent; + line-height: 1; +} + +.phpdocumentor-topnav__menu-item a:hover { + transform: perspective(15rem) translateY(.1rem); + border-bottom: 1px dotted var(--text-color); +} + +@media (min-width: 1000px) { + .phpdocumentor-topnav { + max-height: none; + overflow: visible; + flex-basis: auto; + } + + .phpdocumentor-topnav__menu { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + } + + .phpdocumentor-topnav__menu-item, + .phpdocumentor-topnav__menu-item.-social { + width: auto; + display: inline; + text-align: right; + padding: 0 0 0 var(--spacing-md) + } +} +.phpdocumentor-sidebar { + margin: 0; + overflow: hidden; + max-height: 0; +} + +.phpdocumentor .phpdocumentor-sidebar .phpdocumentor-list { + padding: var(--spacing-xs) var(--spacing-md); + list-style: none; + margin: 0; +} + +.phpdocumentor .phpdocumentor-sidebar li { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + padding: 0 0 var(--spacing-xxxs) var(--spacing-md); +} + +.phpdocumentor .phpdocumentor-sidebar abbr, +.phpdocumentor .phpdocumentor-sidebar a { + text-decoration: none; + border-bottom: none; + color: var(--text-color); + font-size: var(--text-md); + padding-left: 0; + transition: padding-left .4s ease-out; +} + +.phpdocumentor .phpdocumentor-sidebar a:hover, +.phpdocumentor .phpdocumentor-sidebar a.-active { + padding-left: 5px; + font-weight: 600; +} + +.phpdocumentor .phpdocumentor-sidebar__category > * { + border-left: 1px solid var(--primary-color-lighten); +} + +.phpdocumentor .phpdocumentor-sidebar__category { + margin-bottom: var(--spacing-lg); +} + +.phpdocumentor .phpdocumentor-sidebar__category-header { + font-size: var(--text-md); + margin-top: 0; + margin-bottom: var(--spacing-xs); + color: var(--link-color-primary); + font-weight: 600; + border-left: 0; +} + +.phpdocumentor .phpdocumentor-sidebar__root-package, +.phpdocumentor .phpdocumentor-sidebar__root-namespace { + font-size: var(--text-md); + margin: 0; + padding-top: var(--spacing-xs); + padding-left: var(--spacing-md); + color: var(--text-color); + font-weight: normal; +} + +@media (min-width: 550px) { + .phpdocumentor-sidebar { + border-right: var(--sidebar-border-color) solid 1px; + } +} + +.phpdocumentor-sidebar__menu-button { + position: absolute; + top: -100%; + left: -100%; +} + +.phpdocumentor-sidebar__menu-icon { + font-size: var(--text-md); + font-weight: 600; + background: var(--primary-color); + color: white; + margin: 0 0 var(--spacing-lg); + display: block; + padding: var(--spacing-sm); + text-align: center; + border-radius: 3px; + text-transform: uppercase; + letter-spacing: .15rem; +} + +.phpdocumentor-sidebar__menu-button:checked ~ .phpdocumentor-sidebar { + max-height: 100%; + padding-top: var(--spacing-md); +} + +@media (min-width: 550px) { + .phpdocumentor-sidebar { + overflow: visible; + max-height: 100%; + } + + .phpdocumentor-sidebar__menu-icon { + display: none; + } +} +.phpdocumentor-admonition { + border: 1px solid var(--admonition-border-color); + border-radius: var(--border-radius-base-size); + border-color: var(--primary-color-lighten); + background-color: var(--primary-color-lighter); + padding: var(--spacing-lg); + margin: var(--spacing-lg) 0; + display: flex; + flex-direction: row; + align-items: flex-start; +} + +.phpdocumentor-admonition p:last-of-type { + margin-bottom: 0; +} + +.phpdocumentor-admonition--success, +.phpdocumentor-admonition.-success { + border-color: var(--admonition-success-color); +} + +.phpdocumentor-admonition__icon { + margin-right: var(--spacing-md); + color: var(--primary-color); + max-width: 3rem; +} +.phpdocumentor ul.phpdocumentor-breadcrumbs { + font-size: var(--text-md); + list-style: none; + margin: 0; + padding: 0; +} + +.phpdocumentor ul.phpdocumentor-breadcrumbs a { + color: var(--text-color); + text-decoration: none; +} + +.phpdocumentor ul.phpdocumentor-breadcrumbs > li { + display: inline-block; + margin: 0; +} + +.phpdocumentor ul.phpdocumentor-breadcrumbs > li + li:before { + color: var(--dark-gray); + content: "\\\A0"; + padding: 0; +} +.phpdocumentor .phpdocumentor-back-to-top { + position: fixed; + bottom: 2rem; + font-size: 2.5rem; + opacity: .25; + transition: all .3s ease-in-out; + right: 2rem; +} + +.phpdocumentor .phpdocumentor-back-to-top:hover { + color: var(--link-color-primary); + opacity: 1; +} +.phpdocumentor-search { + position: relative; + display: none; /** disable by default for non-js flow */ + opacity: .3; /** white-out default for loading indication */ + transition: opacity .3s, background .3s; + margin: var(--spacing-sm) 0; + flex: 1; + min-width: 100%; +} + +.phpdocumentor-search label { + display: flex; + align-items: center; + flex: 1; +} + +.phpdocumentor-search__icon { + color: var(--primary-color); + margin-right: var(--spacing-sm); + width: 1rem; + height: 1rem; +} + +.phpdocumentor-search--enabled { + display: flex; +} + +.phpdocumentor-search--active { + opacity: 1; +} + +.phpdocumentor-search input:disabled { + background-color: lightgray; +} + +.phpdocumentor-search__field:focus, +.phpdocumentor-search__field { + margin-bottom: 0; + border: 0; + border-bottom: 2px solid var(--primary-color); + padding: 0; + border-radius: 0; + flex: 1; +} + +@media (min-width: 1000px) { + .phpdocumentor-search { + min-width: auto; + max-width: 20rem; + margin: 0 0 0 auto; + } +} +.phpdocumentor-search-results { + backdrop-filter: blur(5px); + background: var(--popover-background-color); + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + padding: 0; + opacity: 1; + pointer-events: all; + + transition: opacity .3s, background .3s; +} + +.phpdocumentor-search-results--hidden { + background: transparent; + backdrop-filter: blur(0); + opacity: 0; + pointer-events: none; +} + +.phpdocumentor-search-results__dialog { + width: 100%; + background: white; + max-height: 100%; + display: flex; + flex-direction: column; +} + +.phpdocumentor-search-results__body { + overflow: auto; +} + +.phpdocumentor-search-results__header { + padding: var(--spacing-lg); + display: flex; + justify-content: space-between; + background: var(--primary-color-darken); + color: white; + align-items: center; +} + +.phpdocumentor-search-results__close { + font-size: var(--text-xl); + background: none; + border: none; + padding: 0; + margin: 0; +} + +.phpdocumentor .phpdocumentor-search-results__title { + font-size: var(--text-xl); + margin-bottom: 0; +} + +.phpdocumentor-search-results__entries { + list-style: none; + padding: 0 var(--spacing-lg); + margin: 0; +} + +.phpdocumentor-search-results__entry { + border-bottom: 1px solid var(--table-separator-color); + padding: var(--spacing-sm) 0; + text-align: left; +} + +.phpdocumentor-search-results__entry a { + display: block; +} + +.phpdocumentor-search-results__entry small { + margin-top: var(--spacing-xs); + margin-bottom: var(--spacing-md); + color: var(--primary-color-darker); + display: block; + word-break: break-word; +} + +.phpdocumentor-search-results__entry h3 { + font-size: var(--text-lg); + margin: 0; +} + +@media (min-width: 550px) { + .phpdocumentor-search-results { + padding: 0 var(--spacing-lg); + } + + .phpdocumentor-search-results__entry h3 { + font-size: var(--text-xxl); + } + + .phpdocumentor-search-results__dialog { + margin: var(--spacing-xl) auto; + max-width: 40rem; + background: white; + border: 1px solid silver; + box-shadow: 0 2px 5px silver; + max-height: 40rem; + border-radius: 3px; + } +} +.phpdocumentor-modal { + position: fixed; + width: 100vw; + height: 100vh; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; +} + +.phpdocumentor-modal__open { + visibility: visible; + opacity: 1; + transition-delay: 0s; +} + +.phpdocumentor-modal-bg { + position: absolute; + background: gray; + opacity: 50%; + width: 100%; + height: 100%; +} + +.phpdocumentor-modal-container { + border-radius: 1em; + background: #fff; + position: relative; + padding: 2em; + box-sizing: border-box; + max-width:100vw; +} + +.phpdocumentor-modal__close { + position: absolute; + right: 0.75em; + top: 0.75em; + outline: none; + appearance: none; + color: var(--primary-color); + background: none; + border: 0px; + font-weight: bold; + cursor: pointer; +} +.phpdocumentor-on-this-page__sidebar { + display: none; +} + +.phpdocumentor-on-this-page__title { + display: block; + font-weight: bold; + margin-bottom: var(--spacing-sm); + color: var(--link-color-primary); +} + +@media (min-width: 1000px) { + .phpdocumentor-on-this-page__sidebar { + display: block; + position: relative; + } + + .phpdocumentor-on-this-page__content::-webkit-scrollbar, + [scrollbars]::-webkit-scrollbar { + height: 8px; + width: 8px; + } + + .phpdocumentor-on-this-page__content::-webkit-scrollbar-corner, + [scrollbars]::-webkit-scrollbar-corner { + background: 0; + } + + .phpdocumentor-on-this-page__content::-webkit-scrollbar-thumb, + [scrollbars]::-webkit-scrollbar-thumb { + background: rgba(128,134,139,0.26); + border-radius: 8px; + } + + .phpdocumentor-on-this-page__content { + position: sticky; + height: calc(100vh - var(--header-height)); + overflow-y: auto; + border-left: 1px solid var(--sidebar-border-color); + padding-left: var(--spacing-lg); + font-size: 90%; + top: -1px; /* Needed for the javascript to make the .-stuck trick work */ + flex: 0 1 auto; + width: 15vw; + } + + .phpdocumentor-on-this-page__content.-stuck { + height: 100vh; + } + + .phpdocumentor-on-this-page__content li { + word-break: break-all; + line-height: normal; + } +} + +/* Used for screen readers and such */ +.visually-hidden { + display: none; +} + +.float-right { + float: right; +} + +.float-left { + float: left; +} diff --git a/css/normalize.css b/css/normalize.css new file mode 100644 index 0000000..653dc00 --- /dev/null +++ b/css/normalize.css @@ -0,0 +1,427 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none !important; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: var(--font-monospace); + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/css/template.css b/css/template.css new file mode 100644 index 0000000..898b676 --- /dev/null +++ b/css/template.css @@ -0,0 +1,271 @@ + +.phpdocumentor-content { + position: relative; + display: flex; + gap: var(--spacing-md); +} + +.phpdocumentor-content > section:first-of-type { + width: 75%; + flex: 1 1 auto; +} + +@media (min-width: 1900px) { + .phpdocumentor-content > section:first-of-type { + width: 100%; + flex: 1 1 auto; + } +} + +.phpdocumentor .phpdocumentor-content__title { + margin-top: 0; +} +.phpdocumentor-summary { + font-style: italic; +} +.phpdocumentor-description { + margin-bottom: var(--spacing-md); +} +.phpdocumentor-element { + position: relative; +} + +.phpdocumentor-element .phpdocumentor-element { + border: 1px solid var(--primary-color-lighten); + margin-bottom: var(--spacing-md); + padding: var(--spacing-xs); + border-radius: 5px; +} + +.phpdocumentor-element.-deprecated .phpdocumentor-element__name { + text-decoration: line-through; +} + +@media (min-width: 550px) { + .phpdocumentor-element .phpdocumentor-element { + margin-bottom: var(--spacing-lg); + padding: var(--spacing-md); + } +} + +.phpdocumentor-element__modifier { + font-size: var(--text-xxs); + padding: calc(var(--spacing-base-size) / 4) calc(var(--spacing-base-size) / 2); + color: var(--text-color); + background-color: var(--light-gray); + border-radius: 3px; + text-transform: uppercase; +} + +.phpdocumentor .phpdocumentor-elements__header { + margin-top: var(--spacing-xxl); + margin-bottom: var(--spacing-lg); +} + +.phpdocumentor .phpdocumentor-element__name { + line-height: 1; + margin-top: 0; + font-weight: 300; + font-size: var(--text-lg); + word-break: break-all; + margin-bottom: var(--spacing-sm); +} + +@media (min-width: 550px) { + .phpdocumentor .phpdocumentor-element__name { + font-size: var(--text-xl); + margin-bottom: var(--spacing-xs); + } +} + +@media (min-width: 1200px) { + .phpdocumentor .phpdocumentor-element__name { + margin-bottom: var(--spacing-md); + } +} + +.phpdocumentor-element__package, +.phpdocumentor-element__extends, +.phpdocumentor-element__implements { + display: block; + font-size: var(--text-xxs); + font-weight: normal; + opacity: .7; +} + +.phpdocumentor-element__package .phpdocumentor-breadcrumbs { + display: inline; +} +.phpdocumentor .phpdocumentor-signature { + display: block; + font-size: var(--text-sm); + border: 1px solid #f0f0f0; +} + +.phpdocumentor .phpdocumentor-signature.-deprecated .phpdocumentor-signature__name { + text-decoration: line-through; +} + +@media (min-width: 550px) { + .phpdocumentor .phpdocumentor-signature { + margin-left: calc(var(--spacing-xl) * -1); + width: calc(100% + var(--spacing-xl)); + } +} + +.phpdocumentor-table-of-contents { +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry { + margin-bottom: var(--spacing-xxs); + margin-left: 2rem; + display: flex; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry > a { + flex: 0 1 auto; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry > span { + flex: 1; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry:after { + content: ''; + height: 12px; + width: 12px; + left: 16px; + position: absolute; +} +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-private:after { + background: url('data:image/svg+xml;utf8,') no-repeat; +} +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-protected:after { + left: 13px; + background: url('data:image/svg+xml;utf8,') no-repeat; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry:before { + width: 1.25rem; + height: 1.25rem; + line-height: 1.25rem; + background: transparent url('data:image/svg+xml;utf8,') no-repeat center center; + content: ''; + position: absolute; + left: 0; + border-radius: 50%; + font-weight: 600; + color: white; + text-align: center; + font-size: .75rem; + margin-top: .2rem; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-method:before { + content: 'M'; + color: ''; + background-image: url('data:image/svg+xml;utf8,'); +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-function:before { + content: 'M'; + color: ' 96'; + background-image: url('data:image/svg+xml;utf8,'); +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-property:before { + content: 'P' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-constant:before { + content: 'C'; + background-color: transparent; + background-image: url('data:image/svg+xml;utf8,'); +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-class:before { + content: 'C' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-interface:before { + content: 'I' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-trait:before { + content: 'T' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-namespace:before { + content: 'N' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-package:before { + content: 'P' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-enum:before { + content: 'E' +} + +.phpdocumentor-table-of-contents dd { + font-style: italic; + margin-left: 2rem; +} +.phpdocumentor-element-found-in { + display: none; +} + +@media (min-width: 550px) { + .phpdocumentor-element-found-in { + display: block; + font-size: var(--text-sm); + color: gray; + margin-bottom: 1rem; + } +} + +@media (min-width: 1200px) { + .phpdocumentor-element-found-in { + position: absolute; + top: var(--spacing-sm); + right: var(--spacing-sm); + font-size: var(--text-sm); + margin-bottom: 0; + } +} + +.phpdocumentor-element-found-in .phpdocumentor-element-found-in__source { + flex: 0 1 auto; + display: inline-flex; +} + +.phpdocumentor-element-found-in .phpdocumentor-element-found-in__source:after { + width: 1.25rem; + height: 1.25rem; + line-height: 1.25rem; + background: transparent url('data:image/svg+xml;utf8,') no-repeat center center; + content: ''; + left: 0; + border-radius: 50%; + font-weight: 600; + text-align: center; + font-size: .75rem; + margin-top: .2rem; +} +.phpdocumentor-class-graph { + width: 100%; height: 600px; border:1px solid black; overflow: hidden +} + +.phpdocumentor-class-graph__graph { + width: 100%; +} +.phpdocumentor-tag-list__definition { + display: flex; +} + +.phpdocumentor-tag-link { + margin-right: var(--spacing-sm); +} diff --git a/files/GPhpThread.php.txt b/files/GPhpThread.php.txt new file mode 100644 index 0000000..58f455a --- /dev/null +++ b/files/GPhpThread.php.txt @@ -0,0 +1,2086 @@ +ownerPid = getmypid(); + if (!file_exists($filePath)) { + if (!posix_mkfifo($filePath, 0644)) { + $this->success = false; + return; + } + } + + $commChanFd = fopen($filePath, ($isReadMode ? 'r+' : 'w+')); // + mode makes it non blocking too + if ($commChanFd === false) { + $this->success = false; + return; + } + + if (!stream_set_blocking($commChanFd, false)) { + $this->success = false; + fclose($commChanFd); + if ($autoDeletion) @unlink($filePath); + return; + } + $this->commChanFdArr[] = $commChanFd; + + $this->commFilePath = $filePath; + $this->autoDeletion = $autoDeletion; + $this->isReadMode = $isReadMode; + } // }}} + + /** + * Checks if the intercom is initialized and ready for use. + * @return bool + */ + public function isInitialized() { // {{{ + return $this->success; + } // }}} + + /** + * Returns the state of the option automatic deletion of the pipe file. + * @return bool + */ + public function getAutoDeletionFlag() { // {{{ + return $this->autoDeletion; + } // }}} + + /** + * Sets the automatic deletion option for the pipe file during the destruction of current instance. + * @param bool $booleanValue + * @return void + */ + public function setAutoDeletionFlag($booleanValue) { // {{{ + $this->autoDeletion = $booleanValue; + } // }}} + + /** + * Destructor. May try automatically to delete the pipe file. + */ + public function __destruct() { // {{{ + if ($this->success && $this->ownerPid === getmypid()) { + if (isset($this->commChanFdArr[0]) && + is_resource($this->commChanFdArr[0])) { + fclose($this->commChanFdArr[0]); + } + if ($this->autoDeletion) @unlink($this->commFilePath); + } + } // }}} + + /** + * Sends data through the intercom. + * @param string $dataString The data to be sent + * @param int $dataLength The length of the data + * @return bool On success returns true otherwise false is returned. + */ + public function send($dataString, $dataLength) { // {{{ + if ($this->success && !$this->isReadMode) { + //if (defined('DEBUG_MODE')) echo $dataString . '[' . getmypid() . "] sending\n"; + $data = (string)$dataString; + $read = $except = null; + + $commChanFdArr = $this->commChanFdArr; + if (stream_select($read, $commChanFdArr, $except, 1) == 0) return false; + + while ($dataLength > 0) { + $bytesWritten = fwrite($this->commChanFdArr[0], $data); + if ($bytesWritten === false) return false; + $dataLength -= $bytesWritten; + if ($dataLength > 0) { + $commChanFdArr = $this->commChanFdArr; + if (stream_select($read, $commChanFdArr, $except, 10) == 0) + return false; + $data = substr($data, 0, $bytesWritten); + } + if (!isset($this->commChanFdArr[0]) || !is_resource($this->commChanFdArr[0])) break; + } + if ($dataLength <= 0) return true; + } + return false; + } // }}} + + /** + * Receives data from the intercom. + * @param int $timeout The maximum time period in milliseconds during which to wait for data to arrive. + * @return string|null If there is no data up to 700 ms after the method is called it returns NULL otherwise returns the data string itself. + */ + public function receive($timeout = 700) { // {{{ + if (!$this->success || !$this->isReadMode) return false; + if (!isset($this->commChanFdArr[0]) || !is_resource($this->commChanFdArr[0])) return false; + + $commChanFdArr = $this->commChanFdArr; + + $write = $except = null; + $data = null; + + $timeout = abs((int)$timeout); + $timeout *= 1000; // convert us to ms + + if (stream_select($commChanFdArr, $write, $except, 0, $timeout) == 0) return $data; + + do { + $d = fread($this->commChanFdArr[0], 1); + if ($d !== false) $data .= $d; + if (!isset($this->commChanFdArr[0]) || !is_resource($this->commChanFdArr[0])) break; + $commChanFdArr = $this->commChanFdArr; + } while ($d !== false && stream_select($commChanFdArr, $write, $except, 0, 22000) != 0); + + //if (defined('DEBUG_MODE')) echo $data . '[' . getmypid() . "] received\n"; // 4 DEBUGGING + return $data; + } // }}} + + /** + * Checks if there is pending data for receiving. + * @return mixed Returns 0 or false if there is no data up to 15 ms after the method is called. Otherwise returns the number of contained stream resources (usually 1). + */ + public function isReceivingDataAvailable() { // {{{ + if (!$this->success || !$this->isReadMode) return false; + if (!isset($this->commChanFdArr[0]) || !is_resource($this->commChanFdArr[0])) return false; + + $commChanFdArr = $this->commChanFdArr; + $write = null; $except = null; + return (stream_select($commChanFdArr, $write, $except, 0, 15000) != 0); + } // }}} +} // }}} + + +/** + * Critical section for sharing data between multiple processes. + * It provides a slower data-safe manipulating methods and unsafe faster methods. + * @see \GPhpThreadIntercom \GPhpThreadIntercom is used for synchronization between the different processes. + * @api + */ +class GPhpThreadCriticalSection // {{{ +{ + /** @internal */ + private $uniqueId = 0; // the identifier of a concrete instance + + /** @internal */ + private static $uniqueIdSeed = 0; // the uniqueId index seed + + /** @internal */ + private static $instancesCreatedEverAArr = array(); // contain all the instances that were ever created of this class + /** @internal */ + private static $threadsForRemovalAArr = array(); // contain all the instances that were terminated; used to make connection with $mastersThreadSpecificData + + /** @internal */ + private $creatorPid; + /** @internal */ + private $pipeDir = ''; + /** @internal */ + private $ownerPid = false; // the thread PID owning the critical section + /** @internal */ + private $myPid; // point of view of the current instance + + /** @internal */ + private $sharedData = array('rel' => array(), 'unrel' => array()); // variables shared in one CS instance among all threads ; two sections are provided reliable one that requires locking of the critical section and unreliable one that does not require locking + + /** @internal */ + private $mastersThreadSpecificData = array(); // specific per each thread variables / the host is the master parent + + // ======== thread specific variables ======== + /** @internal */ + private $intercomWrite = null; + /** @internal */ + private $intercomRead = null; + /** @internal */ + private $intercomInterlocutorPid = null; + /** @internal */ + private $dispatchPriority = 0; + // =========================================== + + /** + * @internal Special variable used in PHP 5.3 to emulate a context-specific use operator with lambdas + */ + private $bindVariable; + /** + * @internal Special variable used in PHP 5.3 to emulate a context-specific use operator with lambdas + */ + private static $bindStaticVariable; + + /** @internal */ + private static $ADDORUPDATESYN = '00', $ADDORUPDATEACK = '01', $ADDORUPDATENACK = '02', + $UNRELADDORUPDATESYN = '03', $UNRELADDORUPDATEACK = '04', $UNRELADDORUPDATENACK = '05', + + $ERASESYN = '06', $ERASEACK = '07', $ERASENACK = '08', + $UNRELERASESYN = '09', $UNRELERASEACK = '10', $UNRELERASENACK = '11', + + $READSYN = '12', $READACK = '13', $READNACK = '14', + $UNRELREADSYN = '15', $UNRELREADACK = '16', $UNRELREADNACK = '17', + + $READALLSYN = '18', $READALLACK = '19', $READALLNACK = '20', + + $LOCKSYN = '21', $LOCKACK = '22', $LOCKNACK = '23', + $UNLOCKSYN = '24', $UNLOCKACK = '25', $UNLOCKNACK = '26'; + + /** @internal */ + private static $ADDORUPDATEACT = 1, $UNRELADDORUPDATEACT = 2, + $ERASEACT = 3, $UNRELERASEACT = 4, + $READACT = 5, $UNRELREADACT = 6, $READALLACT = 7; + + /** + * Constructor. + * @param string $pipeDirectory The directory where the pipe files for the inter-process communication will be stored. + */ + public function __construct($pipeDirectory = '/dev/shm') { // {{{ + $this->uniqueId = self::$uniqueIdSeed++; + + self::$instancesCreatedEverAArr[$this->uniqueId] = &$this; + + $this->creatorPid = getmypid(); + $this->pipeDir = rtrim($pipeDirectory, ' /') . '/'; + } // }}} + + /** + * Destructor. + */ + public function __destruct() { // {{{ + $this->intercomRead = null; + $this->intercomWrite = null; + if (self::$instancesCreatedEverAArr !== null) + unset(self::$instancesCreatedEverAArr[$this->uniqueId]); + } // }}} + + /** + * Initializes the critical section. + * @param int $afterForkPid The process identifier obtained after the execution of a fork() used to differentiate between different processes - pseudo threads. + * @param int $threadId The internal to the GPhpThread identifier of the current thread instance which is unique identifier in the context of the current process. + * @return bool On success returns true otherwise false. + */ + public function initialize($afterForkPid, $threadId) { // {{{ + $this->myPid = getmypid(); + + $retriesLimit = 60; + + if ($this->myPid == $this->creatorPid) { // parent + $i = 0; + do { + $intercomWrite = new GPhpThreadIntercom("{$this->pipeDir}gphpthread_{$this->uniqueId}_s{$this->myPid}-d{$afterForkPid}", false, true); + if ($intercomWrite->isInitialized()) { + $i = $retriesLimit; + } else { + ++$i; + usleep(mt_rand(5000, 80000)); + } + } while ($i < $retriesLimit); + + $i = 0; + do { + $intercomRead = new GPhpThreadIntercom("{$this->pipeDir}gphpthread_{$this->uniqueId}_s{$afterForkPid}-d{$this->myPid}", true, true); + if ($intercomRead->isInitialized()) { + $i = $retriesLimit; + } else { + ++$i; + usleep(mt_rand(5000, 80000)); + } + } while ($i < $retriesLimit); + + if ($intercomWrite->isInitialized() && $intercomRead->isInitialized()) { + $this->mastersThreadSpecificData[$threadId] = array( + 'intercomRead' => $intercomRead, + 'intercomWrite' => $intercomWrite, + 'intercomInterlocutorPid' => $afterForkPid, + 'dispatchPriority' => 0 + ); + return true; + } + return false; + } else { // child + self::$instancesCreatedEverAArr = null; // the child must not know for its neighbours + $this->mastersThreadSpecificData = null; // and any details for the threads inside cs instance simulation + self::$threadsForRemovalAArr = null; + + // these point to the same memory location and also become + // aliases of each other which is strange?!? + // so we need to recreate them + unset($this->intercomWrite); + unset($this->intercomRead); + unset($this->intercomInterlocutorPid); + + $this->intercomWrite = null; + $this->intercomRead = null; + $this->intercomInterlocutorPid = null; + + $this->intercomInterlocutorPid = $this->creatorPid; + + $i = 0; + do { + $this->intercomWrite = new GPhpThreadIntercom("{$this->pipeDir}gphpthread_{$this->uniqueId}_s{$this->myPid}-d{$this->creatorPid}", false, true); + + if ($this->intercomWrite->isInitialized()) { + $i = $retriesLimit; + } else { + ++$i; + usleep(mt_rand(5000, 80000)); + } + } while ($i < $retriesLimit); + + $i = 0; + do { + $this->intercomRead = new GPhpThreadIntercom("{$this->pipeDir}gphpthread_{$this->uniqueId}_s{$this->creatorPid}-d{$this->myPid}", true, false); + + if ($this->intercomRead->isInitialized()) { + $i = $retriesLimit; + } else { + ++$i; + usleep(mt_rand(5000, 80000)); + } + } while ($i < $retriesLimit); + + if (!$this->intercomWrite->isInitialized()) $this->intercomWrite = null; + if (!$this->intercomRead->isInitialized()) $this->intercomRead = null; + if ($this->intercomWrite == null || $this->intercomRead == null) { + $this->intercomInterlocutorPid = null; + return false; + } + + return true; + } + return false; + } // }}} + + + /** + * Cleans pipe files garbage left from any ungracefully terminated instances. + * @return int The total number of unused, cleaned pipe garbage files. + */ + public function cleanPipeGarbage() { // {{{ + $i = 0; + $dirFp = @opendir($this->pipeDir); + if ($dirFp !== false) { + while (($fileName = readdir($dirFp)) !== false) { + if ($fileName[0] != '.' && is_file($this->pipeDir . $fileName)) { + if (preg_match("/^gphpthread_\d+_s(\d+)\-d(\d+)$/", $fileName, $matches)) { + if (!posix_kill($matches[1], 0) && !posix_kill($matches[2], 0)) { + if (@unlink($this->pipeDir . $fileName)) { + ++$i; + } + } + } + } + } + closedir($dirFp); + } + return $i; + } // }}} + + /** + * Finalization of a thread instance that ended and soon will be destroyed. + * @param int $threadId The internal thread identifier. + * @return void + */ + public function finalize($threadId) { // {{{ + unset($this->mastersThreadSpecificData[$threadId]); + } // }}} + + /** + * Confirms if the current thread has the ownership of the critical section associated with it. + * @return bool + */ + private function doIOwnIt() { // {{{ + return ($this->ownerPid !== false && $this->ownerPid == $this->myPid); + } // }}} + + /** + * Encodes data in a message that will be sent to the thread process dispatcher. + * @param string $msg The message type identifier. + * @param string $name The variable name whose data is going to be sent. + * @param mixed $value The current value of the desired for sending variable. + * @return string The composed message string + */ + private function encodeMessage($msg, $name, $value) { // {{{ + // 2 decimal digits message code, 10 decimal digits PID, + // 4 decimal digits name length, name, data + return $msg . sprintf('%010d%04d', $this->myPid, ($name !== null ? strlen($name) : 0)) . $name . serialize($value); + } // }}} + + /** + * Decodes encoded from GPhpThread's instance message. + * @param string $encodedMsg The encoded message + * @param string $msg The encoded message type identifier. REFERENCE type. + * @param int $pid The process id of the sender. REFERENCE type. + * @param string $name The variable name whose data was sent. REFERENCE type. + * @param mixed $value The variable data contained in the encoded message. REFERENCE type. + * @return void + */ + private function decodeMessage($encodedMsg, &$msg, &$pid, &$name, &$value) { // {{{ + // 2 decimal digits message code, 10 decimal digits PID, + // 4 decimal digits name length, name, data + $msg = substr($encodedMsg, 0, 2); + + $pid = substr($encodedMsg, 2, 10); + $pid = (int)preg_filter("/^0{1,9}/", '', $pid); // make the pid decimal number + + $nlength = substr($encodedMsg, 12, 4); + $nlength = (int)preg_filter("/^0{1,3}/", '', $nlength); // make the length decimal number + + if ($nlength == 0) $name = null; + else $name = substr($encodedMsg, 16, $nlength); + + if (strlen($encodedMsg) > 16) $value = unserialize(substr($encodedMsg, 16 + $nlength)); + else $value = null; + } // }}} + + /** + * Checks if the internal intercom is broken. + * @return bool Returns true if the intercom is broken otherwise returns false. + */ + private function isIntercomBroken() { // {{{ + return (empty($this->intercomWrite) || + empty($this->intercomRead) || + empty($this->intercomInterlocutorPid) || + !$this->isPidAlive($this->intercomInterlocutorPid)); + } // }}} + + /** + * Sends data operation to the main process dispatcher. + * @param string $operation The operation type code. + * @param string $resourceName The name of resource that is holding a particular data that will be "shared". + * @param mixed $resourceValue The value of the resource. + * @return bool Returns true on success otherwise false. + */ + private function send($operation, $resourceName, $resourceValue) { // {{{ + if ($this->isIntercomBroken()) return false; + + $isAlive = true; + + $msg = $this->encodeMessage($operation, $resourceName, $resourceValue); + + if (defined('DEBUG_MODE')) { + $dbgStr = '[' . getmypid() . "] is sending "; + switch ($operation) { + case self::$ADDORUPDATESYN: $dbgStr .= 'ADDORUPDATESYN'; break; + case self::$ADDORUPDATEACK: $dbgStr .= 'ADDORUPDATEACK'; break; + case self::$ADDORUPDATENACK: $dbgStr .= 'ADDORUPDATE_N_ACK'; break; + case self::$UNRELADDORUPDATESYN: $dbgStr .= 'UNRELADDORUPDATESYN'; break; + case self::$UNRELADDORUPDATEACK: $dbgStr .= 'UNRELADDORUPDATEACK'; break; + case self::$UNRELADDORUPDATENACK: $dbgStr .= 'UNRELADDORUPDATE_N_ACK'; break; + case self::$ERASESYN: $dbgStr .= 'ERASESYN'; break; + case self::$ERASEACK: $dbgStr .= 'ERASEACK'; break; + case self::$ERASENACK: $dbgStr .= 'ERASE_N_ACK'; break; + case self::$UNRELERASESYN: $dbgStr .= 'UNRELERASESYN'; break; + case self::$UNRELERASEACK: $dbgStr .= 'UNRELERASEACK'; break; + case self::$UNRELERASENACK: $dbgStr .= 'UNRELERASE_N_ACK'; break; + case self::$READSYN: $dbgStr .= 'READSYN'; break; + case self::$READACK: $dbgStr .= 'READACK'; break; + case self::$READNACK: $dbgStr .= 'READ_N_ACK'; break; + case self::$UNRELREADSYN: $dbgStr .= 'UNRELREADSYN'; break; + case self::$UNRELREADACK: $dbgStr .= 'UNRELREADACK'; break; + case self::$UNRELREADNACK: $dbgStr .= 'UNRELREAD_N_ACK'; break; + case self::$READALLSYN: $dbgStr .= 'READALLSYN'; break; + case self::$READALLACK: $dbgStr .= 'READALLACK'; break; + case self::$READALLNACK: $dbgStr .= 'READALL_N_ACK'; break; + case self::$LOCKSYN: $dbgStr .= 'LOCKSYN'; break; + case self::$LOCKACK: $dbgStr .= 'LOCKACK'; break; + case self::$LOCKNACK: $dbgStr .= 'LOCK_N_ACK'; break; + case self::$UNLOCKSYN: $dbgStr .= 'UNLOCKSYN'; break; + case self::$UNLOCKACK: $dbgStr .= 'UNLOCKACK'; break; + case self::$UNLOCKNACK: $dbgStr .= 'UNLOCK_N_ACK'; break; + } + echo "{$dbgStr}, {$resourceName}, " . serialize($resourceValue) . " to {$this->intercomInterlocutorPid} /// {$msg}\n"; + } + + do { + $isSent = $this->intercomWrite->send($msg, strlen($msg)); + if (!$isSent) { + $isAlive = $this->isPidAlive($this->intercomInterlocutorPid); + if ($isAlive) { + for ($i = 0; $i < 120; ++$i) { } + usleep(mt_rand(10000, 200000)); + } + } + + } while ((!$isSent) && $isAlive); + + return $isSent; + } // }}} + + /** + * Receives data operation from the main process dispatcher. + * @param string $message The operation type code. REFERENCE type. + * @param int $pid The process id of the sender "thread". REFERENCE type. + * @param string $resourceName The name of resource that is holding a particular data that will be "shared". REFERENCE type. + * @param mixed $resourceValue The value of the resource. REFERENCE type. + * @param int $timeInterval Internal wait time interval in milliseconds between each data check. + * @return bool Returns true on success otherwise false. + */ + private function receive(&$message, &$pid, &$resourceName, &$resourceValue, $timeInterval = 700) { // {{{ + if ($this->isIntercomBroken()) return false; + + $data = null; + $isAlive = true; + + do { + $data = $this->intercomRead->receive($timeInterval); + $isDataEmpty = empty($data); + if ($isDataEmpty) { + $isAlive = $this->isPidAlive($this->intercomInterlocutorPid); + if ($isAlive) { + for ($i = 0; $i < 120; ++$i) { } + usleep(mt_rand(10000, 200000)); + } + } + } while ($isDataEmpty && $isAlive); + + if (!$isDataEmpty) + $this->decodeMessage($data, $message, $pid, $resourceName, $resourceValue); + + if (defined('DEBUG_MODE')) { + $dbgStr = '[' . getmypid() . "] received "; + switch ($message) { + case self::$ADDORUPDATESYN: $dbgStr .= 'ADDORUPDATESYN'; break; + case self::$ADDORUPDATEACK: $dbgStr .= 'ADDORUPDATEACK'; break; + case self::$ADDORUPDATENACK: $dbgStr .= 'ADDORUPDATE_N_ACK'; break; + case self::$UNRELADDORUPDATESYN: $dbgStr .= 'UNRELADDORUPDATESYN'; break; + case self::$UNRELADDORUPDATEACK: $dbgStr .= 'UNRELADDORUPDATEACK'; break; + case self::$UNRELADDORUPDATENACK: $dbgStr .= 'UNRELADDORUPDATE_N_ACK'; break; + case self::$ERASESYN: $dbgStr .= 'ERASESYN'; break; + case self::$ERASEACK: $dbgStr .= 'ERASEACK'; break; + case self::$ERASENACK: $dbgStr .= 'ERASE_N_ACK'; break; + case self::$UNRELERASESYN: $dbgStr .= 'UNRELERASESYN'; break; + case self::$UNRELERASEACK: $dbgStr .= 'UNRELERASEACK'; break; + case self::$UNRELERASENACK: $dbgStr .= 'UNRELERASE_N_ACK'; break; + case self::$READSYN: $dbgStr .= 'READSYN'; break; + case self::$READACK: $dbgStr .= 'READACK'; break; + case self::$READNACK: $dbgStr .= 'READ_N_ACK'; break; + case self::$UNRELREADSYN: $dbgStr .= 'UNRELREADSYN'; break; + case self::$UNRELREADACK: $dbgStr .= 'UNRELREADACK'; break; + case self::$UNRELREADNACK: $dbgStr .= 'UNRELREAD_N_ACK'; break; + case self::$READALLSYN: $dbgStr .= 'READALLSYN'; break; + case self::$READALLACK: $dbgStr .= 'READALLACK'; break; + case self::$READALLNACK: $dbgStr .= 'READALL_N_ACK'; break; + case self::$LOCKSYN: $dbgStr .= 'LOCKSYN'; break; + case self::$LOCKACK: $dbgStr .= 'LOCKACK'; break; + case self::$LOCKNACK: $dbgStr .= 'LOCK_N_ACK'; break; + case self::$UNLOCKSYN: $dbgStr .= 'UNLOCKSYN'; break; + case self::$UNLOCKACK: $dbgStr .= 'UNLOCKACK'; break; + case self::$UNLOCKNACK: $dbgStr .= 'UNLOCK_N_ACK'; break; + } + echo "{$dbgStr}, {$resourceName}, " . serialize($resourceValue) . " from {$pid} /// {$data}\n"; + } + + return !$isDataEmpty; + } // }}} + + /** + * Tries to lock the critical section. + * @return bool Returns true on success otherwise false. + */ + private function requestLock() { // {{{ + $msg = $pid = $name = $value = null; + + if (!$this->send(self::$LOCKSYN, $name, $value)) return false; + + if (!$this->receive($msg, $pid, $name, $value)) return false; + + if ($msg != self::$LOCKACK) + return false; + + $this->ownerPid = $this->myPid; + return true; + } // }}} + + /** + * Tries to unlock the critical section. + * @return bool Returns true on success otherwise false. + */ + private function requestUnlock() { // {{{ + $msg = $pid = $name = $value = null; + + if (!$this->send(self::$UNLOCKSYN, $name, $value)) + return false; + + if (!$this->receive($msg, $pid, $name, $value)) + return false; + + if ($msg != self::$UNLOCKACK) + return false; + + $this->ownerPid = false; + return true; + } // }}} + + /** + * Executes data operation on the internal shared data container. + * @param string $actionType The performed operation code. + * @param string $name The name of the resource. + * @param mixed $value The value of the resource. + * @return bool Returns true on success otherwise false. + */ + private function updateDataContainer($actionType, $name, $value) { // {{{ + $result = false; + + $msg = null; + $pid = null; + + switch ($actionType) { + case self::$ADDORUPDATEACT: + if ($name === null || $name === '') break; + if (!$this->send(self::$ADDORUPDATESYN, $name, $value)) break; + if (!$this->receive($msg, $pid, $name, $value)) break; + if ($msg == self::$ADDORUPDATEACK) { + $result = true; + $this->sharedData['rel'][$name] = $value; + } + break; + + case self::$UNRELADDORUPDATEACT: + if ($name === null || $name === '') break; + if (!$this->send(self::$UNRELADDORUPDATESYN, $name, $value)) break; + if (!$this->receive($msg, $pid, $name, $value)) break; + if ($msg == self::$UNRELADDORUPDATEACK) { + $result = true; + $this->sharedData['unrel'][$name] = $value; + } + break; + + case self::$ERASEACT: + if ($name === null || $name === '') break; + if (!$this->send(self::$ERASESYN, $name, $value)) break; + if (!$this->receive($msg, $pid, $name, $value)) break; + if ($msg == self::$ERASEACK) { + $result = true; + unset($this->sharedData['rel'][$name]); + } + break; + + case self::$UNRELERASEACT: + if ($name === null || $name === '') break; + if (!$this->send(self::$UNRELERASESYN, $name, $value)) break; + if (!$this->receive($msg, $pid, $name, $value)) break; + if ($msg == self::$UNRELERASEACK) { + $result = true; + unset($this->sharedData['unrel'][$name]); + } + break; + + case self::$READACT: + if ($name === null || $name === '') break; + if (!$this->send(self::$READSYN, $name, $value)) break; + if (!$this->receive($msg, $pid, $name, $value)) break; + if ($msg == self::$READACK) { + $result = true; + $this->sharedData['rel'][$name] = $value; + } + break; + + case self::$UNRELREADACT: + if ($name === null || $name === '') break; + if (!$this->send(self::$UNRELREADSYN, $name, $value)) break; + if (!$this->receive($msg, $pid, $name, $value)) break; + if ($msg == self::$UNRELREADACK) { + $result = true; + $this->sharedData['unrel'][$name] = $value; + } + break; + + case self::$READALLACT: + if (!$this->send(self::$READALLSYN, $name, $value)) break; + if (!$this->receive($msg, $pid, $name, $value)) break; + if ($msg == self::$READALLACK) { + $result = true; + $this->sharedData = $value; + } + break; + } + + return $result; + } // }}} + + /** + * Checks if specific process id is still alive. + * @param int $pid The process identifier. + * @return bool Returns true if the pid is alive otherwise returns false. + */ + private function isPidAlive($pid) { // {{{ + if ($pid === false) return false; + return posix_kill($pid, 0); + } // }}} + + + /** + * Sort by occurred lock and dispatch priority. This is a workaround + * method required for PHP 5.3 and relies on an initialized + * $bindVariable inside this class. + * @param mixed $a The first key to be taken into account. + * @param mixed $b The second key to be taken into account. + * @return int -1, 0 or 1 depending on which key is more preferable. + */ + private function sortByLockAndDispatchPriority($a, $b) { // {{{ + $presentIndexA = false; + if (isset($this->bindVariable->mastersThreadSpecificData[$a])) { + if ($this->bindVariable->mastersThreadSpecificData[$a]['intercomInterlocutorPid'] === $this->bindVariable->ownerPid) return -1; + $presentIndexA = true; + } + $presentIndexB = false; + if (isset($this->bindVariable->mastersThreadSpecificData[$b])) { + if ($this->bindVariable->mastersThreadSpecificData[$b]['intercomInterlocutorPid'] === $this->bindVariable->ownerPid) return 1; + $presentIndexB = true; + } + if (!($presentIndexA && $presentIndexB)) { + return ($presentIndexA ? -1 : (int)$presentIndexB); + } + return (int)($this->bindVariable->mastersThreadSpecificData[$a]['dispatchPriority'] < $this->bindVariable->mastersThreadSpecificData[$b]['dispatchPriority']); + } // }}} + + /** + * Sort by occurred lock, dispatch priority and most threads using + * the critical section. This is workaround method required for + * PHP 5.3 and relies on an initialized $bindVariable inside this + * class. + * @param mixed $a The first key to be taken into account. + * @param mixed $b The second key to be taken into account. + * @return int -1, 0 or 1 depending on which key is more preferable. + */ + private static function sortByLockDispatchPriorityAndMostThreadsInside($a, $b) { // {{{ + // the locker thread is with highest priority + if (self::$bindStaticVariable[$a]->mastersThreadSpecificData['intercomInterlocutorPid'] == self::$bindStaticVariable[$a]->ownerPid) return -1; + if (self::$bindStaticVariable[$b]->mastersThreadSpecificData['intercomInterlocutorPid'] == self::$bindStaticVariable[$b]->ownerPid) return 1; + + // deal with the case of critical sections with no threads + if (!empty(self::$bindStaticVariable[$a]->mastersThreadSpecificData) && empty(self::$bindStaticVariable[$b]->mastersThreadSpecificData)) { return -1; } // a + else if (empty(self::$bindStaticVariable[$a]->mastersThreadSpecificData) && !empty(self::$bindStaticVariable[$b]->mastersThreadSpecificData)) { return 1; } // b + else if (empty(self::$bindStaticVariable[$b]->mastersThreadSpecificData) && empty(self::$bindStaticVariable[$b]->mastersThreadSpecificData)) { return 0; } // a + + // gather the thread dispatch priorities for the compared critical sections + + $dispPriorTableA = array(); // priority value => occurrences count + $dispPriorTableB = array(); // priority value => occurrences count + + foreach (self::$bindStaticVariable[$a]->mastersThreadSpecificData as $thrdSpecificData) + @$dispPriorTableA[$thrdSpecificData['dispatchPriority']] += 1; + + foreach (self::$bindStaticVariable[$b]->mastersThreadSpecificData as $thrdSpecificData) + @$dispPriorTableB[$thrdSpecificData['dispatchPriority']] += 1; + + // both critical sections have threads + + // make the tables to have the same amount of keys (rows) + foreach ($dispPriorTableA as $key => $value) + @$dispPriorTableB[$key] = $dispPriorTableB[$key]; // this is done on purpose + foreach ($dispPriorTableB as $key => $value) + @$dispPriorTableA[$key] = $dispPriorTableA[$key]; + + ksort($dispPriorTableA); + ksort($dispPriorTableB); + + // compare the tables while taking into account the priority + // and the thread count that have it per critical section + + foreach ($dispPriorTableA as $key => $value) { + if ($value < $dispPriorTableB[$key]) { return 1; } // b + else if ($value > $dispPriorTableB[$key]) { return -1; } // a + } + + return 0; // a + } // }}} + + /** + * Dispatcher responsible for the thread intercommunication and communication with their parent process. + * @param bool $useBlocking On true blocks the internal execution until communication data is available for the current dispatched thread otherwise it skips it. + * @return void + */ + public static function dispatch($useBlocking = false) { // {{{ + $NULL = null; + + // prevent any threads to run their own dispatchers + if ((self::$instancesCreatedEverAArr === null) || (count(self::$instancesCreatedEverAArr) == 0)) + return; + + // for checking SIGCHLD child signals informing that a particular "thread" was paused + $sigSet = array(SIGCHLD); + $sigInfo = array(); + + + // begin the dispatching process + foreach (self::$instancesCreatedEverAArr as $instId => &$inst) { // loop through ALL active instances of GPhpCriticalSection + + foreach ($inst->mastersThreadSpecificData as $threadId => &$specificDataAArr) { // loop though the threads per each instance in GPhpCriticalSection + // checking for child signals informing that a thread has exited or was paused + while (pcntl_sigtimedwait($sigSet, $sigInfo) == SIGCHLD) { + if ($sigInfo['code'] >= 0 && $sigInfo['code'] <= 3) { // child has exited + self::$threadsForRemovalAArr[$sigInfo['pid']] = $sigInfo['pid']; + } else if ($sigInfo['code'] == 5) { // stopped (paused) child + $specificDataAArr['dispatchPriority'] = 0; // make the dispatch priority lowest + } else if ($sigInfo['code'] == 6) { // resume stopped (paused) child + $specificDataAArr['dispatchPriority'] = 1; // increase little bit the priority since we expect interaction with the critical section + } + } + + $inst->intercomInterlocutorPid = &$specificDataAArr['intercomInterlocutorPid']; + + if (isset(self::$threadsForRemovalAArr[$inst->intercomInterlocutorPid])) { + unset($inst->mastersThreadSpecificData[$threadId]); + continue; + } + + $inst->intercomRead = &$specificDataAArr['intercomRead']; + $inst->intercomWrite = &$specificDataAArr['intercomWrite']; + $inst->dispatchPriority = &$specificDataAArr['dispatchPriority']; + + if (!$useBlocking && !$inst->intercomRead->isReceivingDataAvailable()) { + $inst->dispatchPriority = 0; + if ($inst->isIntercomBroken()) { + unset($inst->mastersThreadSpecificData[$threadId]); // remove the thread from the dispatching list as soon as we can + } + continue; + } + + self::dataDispatch($inst, $threadId); + + $mostPrioritizedThreadId = NULL; + if ($inst->dispatchPriority !== 2) { + foreach ($inst->mastersThreadSpecificData as $threadId2 => &$specificDataAArr2) { + if ($specificDataAArr2['dispatchPriority'] === 2) { + $mostPrioritizedThreadId = $threadId2; + } + } + } else { + $mostPrioritizedThreadId = $threadId; + } + + if ($mostPrioritizedThreadId !== NULL && $mostPrioritizedThreadId !== $threadId) { + $inst->intercomInterlocutorPid = &$inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['intercomInterlocutorPid']; + $inst->intercomRead = &$inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['intercomRead']; + $inst->intercomWrite = &$inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['intercomWrite']; + $inst->dispatchPriority = &$inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['dispatchPriority']; + + if (!$useBlocking && !$inst->intercomRead->isReceivingDataAvailable()) { + $inst->dispatchPriority = 0; + if ($inst->isIntercomBroken()) { + unset($inst->mastersThreadSpecificData[$mostPrioritizedThreadId]); // remove the thread from the dispatching list as soon as we can + } + continue; + } + self::dataDispatch($inst, $threadId); + } + } + + // rearrange the threads in the current critical section + // instance using their new dispatch priority number + // if a lock has already occurred that thread will have the + // highest priority + + $inst->bindVariable = &$inst; + uksort($inst->mastersThreadSpecificData, array($inst, 'sortByLockAndDispatchPriority')); + //uksort($inst->mastersThreadSpecificData, + // function ($a, $b) use ($inst) { + // if ($inst->mastersThreadSpecificData[$a]['intercomInterlocutorPid'] == $inst->ownerPid) return -1; + // if ($inst->mastersThreadSpecificData[$b]['intercomInterlocutorPid'] == $inst->ownerPid) return 1; + // return $inst->mastersThreadSpecificData[$a]['dispatchPriority'] < $inst->mastersThreadSpecificData[$b]['dispatchPriority']; + // } + //); + + $inst->intercomInterlocutorPid = &$NULL; + $inst->intercomRead = &$NULL; + $inst->intercomWrite = &$NULL; + $inst->dispatchPriority = &$NULL; + } + + // make sure that no terminated threads are left in the internal thread + // dispatching list that all instances of GPhpThreadCriticalSection have + foreach (self::$instancesCreatedEverAArr as $instId => &$inst) { + foreach ($inst->mastersThreadSpecificData as $threadId => &$specificDataAArr) { + $inst->intercomInterlocutorPid = &$specificDataAArr['intercomInterlocutorPid']; + if (isset(self::$threadsForRemovalAArr[$inst->intercomInterlocutorPid])) + unset($inst->mastersThreadSpecificData[$threadId]); + } + $inst->intercomInterlocutorPid = &$NULL; + } + self::$threadsForRemovalAArr = array(); + + // rearrange the active instances of GPhpThreadCriticalSection in the + // following priority order (the higher the number the bigger the priority): + + // 2. the instance with the thread that has currently locked the critical section + // 1. instances with threads with the highest dispatch priority + // 0. instances with the most threads inside + + self::$bindStaticVariable = &self::$instancesCreatedEverAArr; + uksort(self::$bindStaticVariable, + array('GPhpThreadCriticalSection', 'sortByLockDispatchPriorityAndMostThreadsInside')); + + //$instCrtdEver = &self::$instancesCreatedEverAArr; + //uksort($instCrtdEver, + // function ($a, $b) use ($instCrtdEver) { + // // the locker thread is with highest priority + // if ($instCrtdEver[$a]->mastersThreadSpecificData['intercomInterlocutorPid'] == $instCrtdEver[$a]->ownerPid) return -1; + // if ($instCrtdEver[$b]->mastersThreadSpecificData['intercomInterlocutorPid'] == $instCrtdEver[$b]->ownerPid) return 1; + // + // // deal with the case of critical sections with no threads + // if (!empty($instCrtdEver[$a]->mastersThreadSpecificData) && empty($instCrtdEver[$b]->mastersThreadSpecificData)) { return -1; } // a + // else if (empty($instCrtdEver[$a]->mastersThreadSpecificData) && !empty($instCrtdEver[$b]->mastersThreadSpecificData)) { return 1; } // b + // else if (empty($instCrtdEver[$b]->mastersThreadSpecificData) && empty($instCrtdEver[$b]->mastersThreadSpecificData)) { return 0; } // a + // + // // gather the thread dispatch priorities for the compared critical sections + // + // $dispPriorTableA = array(); // priority value => occurrences count + // $dispPriorTableB = array(); // priority value => occurrences count + // + // foreach ($instCrtdEver[$a]->mastersThreadSpecificData as $thrdSpecificData) + // @$dispPriorTableA[$thrdSpecificData['dispatchPriority']] += 1; + // + // foreach ($instCrtdEver[$b]->mastersThreadSpecificData as $thrdSpecificData) + // @$dispPriorTableB[$thrdSpecificData['dispatchPriority']] += 1; + // + // // both critical sections have threads + // + // // make the tables to have the same amount of keys (rows) + // foreach ($dispPriorTableA as $key => $value) + // @$dispPriorTableB[$key] = $dispPriorTableB[$key]; // this is done on purpose + // foreach ($dispPriorTableB as $key => $value) + // @$dispPriorTableA[$key] = $dispPriorTableA[$key]; + // + // ksort($dispPriorTableA); + // ksort($dispPriorTableB); + // + // // compare the tables while taking into account the priority + // // and the thread count that have it per critical section + // + // foreach ($dispPriorTableA as $key => $value) { + // if ($value < $dispPriorTableB[$key]) { return 1; } // b + // else if ($value > $dispPriorTableB[$key]) { return -1; } // a + // } + // + // return 0; // a + // } + //); + + } // }}} + + /** + * Operations on the transferred data dispatch helper. + * @param GPhpThreadCriticalSection $inst The instance of the critical section to work with + * @param int $threadId The identifier of the thread whose critical section is currently dispatched. + * @return void + */ + private static function dataDispatch(&$inst, $threadId) { // {{{ + + $msg = $pid = $name = $value = null; + + // Optimize the data receive timeout for each thread + // based on its: + // 2. priority + // 1. threads count for the current critical section + // 0. total critical sections count + + $dataReceiveTimeoutMs = 700; // default timeout + + $dataReceiveTimeoutReducer = 2 - $inst->dispatchPriority; + $dataReceiveTimeoutReducer += (count($inst->mastersThreadSpecificData) - 1); + $dataReceiveTimeoutReducer += ((count(self::$instancesCreatedEverAArr) * 2) - 1); + + $dataReceiveTimeoutMs /= $dataReceiveTimeoutReducer; + $dataReceiveTimeoutMs = (int)$dataReceiveTimeoutMs; + if ($dataReceiveTimeoutMs == 0) $dataReceiveTimeoutMs = 1; + + // Receive some data + + if (!$inst->receive($msg, $pid, $name, $value, $dataReceiveTimeoutMs)) { + $inst->dispatchPriority = 0; + if ($inst->isIntercomBroken()) unset($inst->threadInstanceContext[$threadId]); // remove the thread from the dispatching list as soon as we can + return; + } + + switch ($msg) { + case GPhpThreadCriticalSection::$LOCKSYN: + $inst->dispatchPriority = 1; + if ($inst->ownerPid !== false && $inst->ownerPid != $pid && $inst->isPidAlive($inst->ownerPid)) { + $inst->send(GPhpThreadCriticalSection::$LOCKNACK, null, $pid); + return; + } + if (!$inst->send(GPhpThreadCriticalSection::$LOCKACK, null, $pid)) return; + $inst->ownerPid = $pid; + $inst->dispatchPriority = 2; + break; + + case GPhpThreadCriticalSection::$UNLOCKSYN: + $inst->dispatchPriority = 1; + if ($inst->ownerPid === false) { + if (!$inst->send(GPhpThreadCriticalSection::$UNLOCKACK, null, $pid)) return; + } + $isOwnerAlive = $inst->isPidAlive($inst->ownerPid); + if (!$isOwnerAlive || $inst->ownerPid == $pid) { + if (!$isOwnerAlive) $inst->ownerPid = false; + if (!$inst->send(GPhpThreadCriticalSection::$UNLOCKACK, null, $pid)) return; + $inst->dispatchPriority = 0; + $inst->ownerPid = false; + } else { + $inst->send(GPhpThreadCriticalSection::$UNLOCKNACK, null, null); + } + break; + + case GPhpThreadCriticalSection::$ADDORUPDATESYN: + $inst->dispatchPriority = 1; + if ($inst->ownerPid !== $pid) { + $inst->send(GPhpThreadCriticalSection::$ADDORUPDATENACK, null, null); + return; + } + if (!$inst->send(GPhpThreadCriticalSection::$ADDORUPDATEACK, $name, null)) return; + $inst->dispatchPriority = 2; + $inst->sharedData['rel'][$name] = $value; + break; + + case GPhpThreadCriticalSection::$UNRELADDORUPDATESYN: + $inst->dispatchPriority = 1; + if (!$inst->send(GPhpThreadCriticalSection::$UNRELADDORUPDATEACK, $name, null)) return; + $inst->dispatchPriority = 2; + $inst->sharedData['unrel'][$name] = $value; + break; + + case GPhpThreadCriticalSection::$ERASESYN: + $inst->dispatchPriority = 1; + if ($inst->ownerPid !== $pid) { + $inst->send(GPhpThreadCriticalSection::$ERASENACK, null, null); + return; + } + if (!$inst->send(GPhpThreadCriticalSection::$ERASEACK, $name, null)) return; + $inst->dispatchPriority = 2; + unset($inst->sharedData['rel'][$name]); + break; + + case GPhpThreadCriticalSection::$UNRELERASESYN: + $inst->dispatchPriority = 1; + if (!$inst->send(GPhpThreadCriticalSection::$ERASEACK, $name, null)) return; + $inst->dispatchPriority = 2; + unset($inst->sharedData['unrel'][$name]); + break; + + case GPhpThreadCriticalSection::$READSYN: + $inst->dispatchPriority = 1; + if ($inst->ownerPid !== $pid) { + $inst->send(GPhpThreadCriticalSection::$READNACK, null, null); + return; + } + $inst->send(GPhpThreadCriticalSection::$READACK, $name, (isset($inst->sharedData['rel'][$name]) || array_key_exists($name, $inst->sharedData['rel']) ? $inst->sharedData['rel'][$name] : null)); + $inst->dispatchPriority = 2; + break; + + case GPhpThreadCriticalSection::$UNRELREADSYN: + $inst->dispatchPriority = 1; + $inst->send(GPhpThreadCriticalSection::$UNRELREADACK, $name, (isset($inst->sharedData['unrel'][$name]) || array_key_exists($name, $inst->sharedData['unrel']) ? $inst->sharedData['unrel'][$name] : null)); + $inst->dispatchPriority = 2; + break; + + case GPhpThreadCriticalSection::$READALLSYN: + $inst->dispatchPriority = 1; + if ($inst->ownerPid !== $pid) { + $inst->send(GPhpThreadCriticalSection::$READALLNACK, null, null); + return; + } + $inst->send(GPhpThreadCriticalSection::$READALLACK, null, $inst->sharedData); + $inst->dispatchPriority = 2; + break; + } + } // }}} + + /** + * Tries to lock the associated with the instance critical section. + * @param bool $useBlocking If it's set to true the method will block until a lock is successfully established. + * @return bool Returns true on success otherwise returns false. + */ + public function lock($useBlocking = true) { // {{{ + if ($this->doIOwnIt()) return true; + + do { + if (!$this->doIOwnIt() || !$this->isPidAlive($this->ownerPid)) { + if ($this->myPid == $this->creatorPid) { // local lock request + $this->ownerPid = $this->myPid; + return true; + } + + do { + $res = $this->requestLock(); + + if ($useBlocking && !$res) { + if ($this->isIntercomBroken()) return false; + for ($i = 0; $i < 120; ++$i) { } + usleep(mt_rand(10000, 200000)); + } + } while ($useBlocking && !$res); + + if (!$res) return false; + + if (!$this->updateDataContainer(self::$READALLACT, null, null)) { + $this->unlock(); + return false; + } + return true; + } + + if ($useBlocking) { + for ($i = 0; $i < 120; ++$i) { } + usleep(mt_rand(10000, 200000)); + } + + } while ($useBlocking && !$this->doIOwnIt()); + + return true; + } // }}} + + /** + * Tries to unlock the associated with the instance critical section. + * @param bool $useBlocking If it's set to true the method will block until an unlock is successfully established. + * @return bool Returns true on success otherwise returns false. + */ + public function unlock($useBlocking = false) { // {{{ + if ($this->doIOwnIt() || $this->ownerPid === false) { + if ($this->myPid == $this->creatorPid) { // local unlock request + $this->ownerPid = false; + return true; + } + + $res = null; + while ((($res = $this->requestUnlock()) === false) && $useBlocking) { + for ($i = 0; $i < 120; ++$i) { } + usleep(mt_rand(10000, 200000)); + } + return $res; + } + return true; + } // }}} + + /** + * Adds or updates shared resource in a reliable, slower way. A lock of the critical section is required. + * @param string $name The name of the resource. + * @param mixed $value The value of the resource. + * @return bool Returns true on success otherwise returns false. + */ + public function addOrUpdateResource($name, $value) { // {{{ + if ($this->doIOwnIt()) { + if ($this->myPid == $this->creatorPid) { // local resource add/update request + $this->sharedData['rel'][$name] = $value; + return true; + } + if (!$this->updateDataContainer(self::$ADDORUPDATEACT, $name, $value)) return false; + return true; + } + return false; + } // }}} + + /** + * Adds or updates shared resource in an unreliable, faster way. A lock of the critical section is NOT required. + * @param string $name The name of the resource. + * @param mixed $value The value of the resource. + * @return bool Returns true on success otherwise returns false. + */ + public function addOrUpdateUnrelResource($name, $value) { // {{{ + if ($this->myPid == $this->creatorPid) { // local resource add/update request + $this->sharedData['unrel'][$name] = $value; + return true; + } + if (!$this->updateDataContainer(self::$UNRELADDORUPDATEACT, $name, $value)) return false; + return true; + } // }}} + + /** + * Removes shared resource in a reliable, slower way. A lock of the critical section is required. + * @param string $name The name of the resource. + * @return bool Returns true on success otherwise returns false. + */ + public function removeResource($name) { // {{{ + if ($this->doIOwnIt() && + isset($this->sharedData['rel'][$name]) || + array_key_exists($name, $this->sharedData['rel'])) { + + if ($this->myPid == $this->creatorPid) { // local resource remove request + unset($this->sharedData['rel'][$name]); + return true; + } + + if (!$this->updateDataContainer(self::$ERASEACT, $name, null)) return false; + return true; + } + return false; + } // }}} + + /** + * Removes shared resource in an unreliable, faster way. A lock of the critical section is NOT required. + * @param string $name The name of the resource. + * @return bool Returns true on success otherwise returns false. + */ + public function removeUnrelResource($name) { // {{{ + if (isset($this->sharedData['unrel'][$name]) || + array_key_exists($name, $this->sharedData['unrel'])) { + + if ($this->myPid == $this->creatorPid) { // local resource remove request + unset($this->sharedData['unrel'][$name]); + return true; + } + + if (!$this->updateDataContainer(self::$UNRELERASEACT, $name, null)) return false; + return true; + } + return false; + } // }}} + + /** + * Returns an reliable resource without trying to ask for it the dispatcher. + * @param string $name The name of the resource. + * @return mixed Returns the resource value or null on failure or if the resource name was not found. + */ + public function getResourceValueFast($name) { // {{{ + return (isset($this->sharedData['rel'][$name]) || array_key_exists($name, $this->sharedData['rel']) ? $this->sharedData['rel'][$name] : null); + } // }}} + + /** + * Returns an unreliable resource without trying to ask for it the dispatcher. + * @param string $name The name of the resource. + * @return mixed Returns the resource value or null on failure or if the resource name was not found. + */ + public function getUnrelResourceValueFast($name) { // {{{ + return (isset($this->sharedData['unrel'][$name]) || array_key_exists($name, $this->sharedData['unrel']) ? $this->sharedData['unrel'][$name] : null); + } // }}} + + /** + * Returns an reliable resource value by asking the dispatcher for it. An ownership of the critical section is required. + * @throws \GPhpThreadException If the critical section ownership is not obtained. + * @param string $name The name of the desired resource. + * @return mixed The resource value or null if the resource was not found. + */ + public function getResourceValue($name) { // {{{ + if (!$this->doIOwnIt()) + throw new \GPhpThreadException('[' . getmypid() . '][' . $this->uniqueId . '] Not owned critical section!'); + + if ($this->myPid == $this->creatorPid) { // local resource read request ; added to keep a consistency with getResourceValueFast + return $this->getResourceValueFast($name); + } + + if (!$this->updateDataContainer(self::$READACT, $name, null)) + throw new \GPhpThreadException('[' . getmypid() . '][' . $this->uniqueId . '] Error while retrieving the value!'); + + return $this->sharedData['rel'][$name]; + } // }}} + + /** + * Returns an unreliable resource value by asking the dispatcher for it. An ownership of the critical section is required. + * @throws \GPhpThreadException If the critical section ownership is not obtained. + * @param string $name The name of the desired resource. + * @return mixed The resource value or null if the resource was not found. + */ + public function getUnrelResourceValue($name) { // {{{ + if ($this->myPid == $this->creatorPid) { // local resource read request ; added to keep a consistency with getResourceValueFast + return $this->getUnrelResourceValueFast($name); + } + + if (!$this->updateDataContainer(self::$UNRELREADACT, $name, null)) + throw new \GPhpThreadException('[' . getmypid() . '][' . $this->uniqueId . '] Error while retrieving the value!'); + + return $this->sharedData['unrel'][$name]; + } // }}} + + /** + * Returns the names of all reliable shared resources. + * @return array An array of (0 => 'resource name1', 1 => 'resource name2', ...) + */ + public function getResourceNames() { // {{{ + return array_keys($this->sharedData['rel']); + } // }}} + + /** + * Returns the names of all unreliable shared resources. + * @return array An array of (0 => 'resource name1', 1 => 'resource name2', ...) + */ + public function getUnrelResourceNames() { // {{{ + return array_keys($this->sharedData['unrel']); + } // }}} +} // }}} + + +/** + * A data container not allowed to be cloned. + * Once created, only REFERENCEs to it are allowed. + * It is NOT protected against fork or direct import()/export(). If that is desired it should be wrapped. + * @throws \GPhpThreadException When caught clone attempts. + */ +final class GPhpThreadNotCloneableContainer implements \Serializable // {{{ +{ + /** @internal */ + private static $seed = 0; + + /** @internal */ + private $id = 0; + + /** @var mixed $variable The container holding the user's value */ + private $variable; + + /** + * Constructor. + */ + public function __construct() { + $this->id = self::$seed++; + } + + /** + * Generates object id. + * @return string The id of the current instance. + */ + public final function __toString() { + return "{$this->id}"; + } + + /** + * Sets the value desired to be held. + * @param mixed $value The value to be held inside this container. + * @return void + * @throws \GPhpThreadException If an instance of \GPhpThreadNotCloneableContainer is passed. + */ + public function import($value) { + if ($value instanceof self) { + throw new \GPhpThreadException("Not allowed cloning of GPhpThreadNotCloneableContainer!"); + } + $this->variable = $value; + } + + /** + * Returns the contained value. + * @return mixed The contained value. + */ + public function export() { + return $this->variable; + } + + /** @internal */ + private function __clone() { + throw new GPhpThreadException("Not allowed cloning of GPhpThreadNotCloneableContainer!"); + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @return string Always empty string + */ + public final function serialize() { + throw new GPhpThreadException("Not allowed cloning of GPhpThreadNotCloneableContainer!"); + return ''; // unlikely + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param string $data The serialized string. + * @param array $options Any options to be provided to unserialize(), as an associative array (introduced in PHP 7). + * @return bool Always false + */ + public final function unserialize($data, $options = array()) { + throw new GPhpThreadException("Not allowed cloning of GPhpThreadNotCloneableContainer!"); + return false; + } + + /** + * PHP 7.4+ alternative serialization technique + * @internal + * @throws \GPhpThreadException Does that every time. + * @return string Always an empty array. + */ + public final function __serialize() { + $this->serialize(); + return array(); // unlikely + } + + /** + * PHP 7.4+ alternative unserialization technique + * @throws \GPhpThreadException Does that every time. + * @internal + * @return void + */ + public final function __unserialize($dataArr) { + $this->unserialize(null); + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @param mixed $value variable value. + * @return void + */ + public final function __set($name, $value) { + throw new GPhpThreadException("Not allowed use of magic method __set()!"); + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @param mixed $value variable value. + * @return NULL Always NULL. + */ + public final function __get($name) { + throw new GPhpThreadException("Not allowed use of magic method __get()!"); + return null; + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @return void + */ + public final function __unset($name) { + throw new GPhpThreadException("Not allowed use of magic method __unset()!"); + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @return NULL Always NULL. + */ + public static final function __set_state($name) { + throw new GPhpThreadException("Not allowed use of magic method __set_state()!"); + return null; + } +} // }}} + + +/** + * A wrapper providing RAII mechanism for locking and unlocking + * purposes of a critical section objects and a similar ones. + * @see \GPhpThreadCriticalSection + * @throws \GPhpThreadException When improperly passed/configured a critical section or clone attempts are made. + * @api + */ +class GPhpThreadLockGuard implements \Serializable // {{{ +{ + /** @var object $criticalSectionObject The critical section that will be un/locked. REFERENCE type. */ + private $criticalSectionObj = NULL; + /** @var string $unlockMethod The unlock method name of the critical section that will be called during an unlock. */ + private $unlockMethod = 'unlock'; + /** @var string $unlockMethodsParams The parameters passed to the critical section's unlock method during an unlock. */ + private $unlockMethodsParams = array(); + + /** + * Constructor. Immediately locks the passed critical section. + * @throws \GPhpThreadException Exception is thrown in case an uninitialized critical section is passed or the specified lock or unlock methods are missing. + * @param object $criticalSectionObj An initialized critical section object or similar. A REFERENCE type. + * @param string $lockMethod The name of the $criticalSectionObj's lock method that will be called. + * @param array $lockMethodParams Parameter that will be passed to the lock method of $criticalSectionObj. + * @param string $unlockMethod The name of the $criticalSectionObj's unlock method that will be called. + * @param array $unlockMethodsParams Parameter that will be passed to the unlock method of $criticalSectionObj. + */ + public final function __construct(&$criticalSectionObj, $lockMethod = 'lock', array $lockMethodParams = array(), + $unlockMethod = 'unlock', array $unlockMethodsParams = array()) { + + $this->criticalSectionObj = &$criticalSectionObj; + + if (!is_object($this->criticalSectionObj)) { + throw new \GPhpThreadException('Uninitialized critical section passed to GPhpThreadLockGuard!'); + } + if (empty($lockMethod) || empty($unlockMethod) || + !method_exists($this->criticalSectionObj, $lockMethod) || + !method_exists($this->criticalSectionObj, $unlockMethod)) { + throw new \GPhpThreadException('Not existing lock/unlock methods in &$criticalSectionObj!'); + } + + $this->unlockMethod = $unlockMethod; + $this->unlockMethodsParams = $unlockMethodsParams; + + call_user_func_array(array($this->criticalSectionObj, $lockMethod), $lockMethodParams); + } + + /** + * Destructor. Immediately unlocks the passed critical section. + */ + public final function __destruct() { + if (!is_object($this->criticalSectionObj)) { + throw new \GPhpThreadException('Uninitialized &$criticalSectionObj attempted to be unlocked via GPhpThreadLockGuard!'); + } + call_user_func_array(array($this->criticalSectionObj, $this->unlockMethod), $this->unlockMethodsParams); + } + + /** @internal */ + private function __clone() { + throw new \GPhpThreadException('Attempted to clone GPhpThreadLockGuard!'); + } + + /** + * @internal + * @return string Always an empty string. + */ + public final function serialize() { + return ''; + } + + /** + * @internal + * @param string $data The serialized string. + * @param array $options Any options to be provided to unserialize(), as an associative array (introduces in PHP 7). + * @return bool Always false. + */ + public final function unserialize($data, $options = array()) { + return false; + } + + /** + * PHP 7.4+ alternative serialization technique + * @internal + * @return string Always an empty array. + */ + public final function __serialize() { + return array(); + } + + /** + * PHP 7.4+ alternative unserialization technique + * @internal + * @return void + */ + public final function __unserialize($dataArr) { + // shall always return nothing + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @param mixed $value variable value. + * @return void + */ + public final function __set($name, $value) { + throw new GPhpThreadException("Not allowed use of magic method __set()!"); + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @param mixed $value variable value. + * @return NULL Always NULL. + */ + public final function __get($name) { + throw new GPhpThreadException("Not allowed use of magic method __get()!"); + return null; + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @return void + */ + public final function __unset($name) { + throw new GPhpThreadException("Not allowed use of magic method __unset()!"); + } + + /** + * @internal + * @throws \GPhpThreadException Does that every time. + * @param mixed $name Variable name. + * @return NULL Always NULL. + */ + public static final function __set_state($name) { + throw new GPhpThreadException("Not allowed use of magic method __set_state()!"); + return null; + } + + /** + * @internal + * @return string 'GPhpThreadLockGuard' always. + */ + public final function __toString() { + return 'GPhpThreadLockGuard'; + } +} // }}} + + +/** + * A heavy thread creation and manipulation class. + * + * Provides purely implemented in php instruments for "thread" creation + * and manipulation. A shell access, pcntl, posix, linux OS and PHP 5.3+ + * are required. + * @api + */ +abstract class GPhpThread // {{{ +{ + /** @internal */ + protected $criticalSection = null; + /** @internal */ + private $parentPid = null; + /** @internal */ + private $childPid = null; + /** @internal */ + private $_childPid = null; + /** @internal */ + private $allowThreadExitCodes = true; + /** @internal */ + private $exitCode = null; + + /** @internal */ + private $amIStarted = false; + + /** @internal */ + private $uniqueId = 0; + /** @internal */ + private static $seed = 0; + + /** @internal */ + private static $originPid = 0; + /** @internal */ + private static $originDynamicDataArr = array(); + + /** @internal */ + private static $isCriticalSectionDispatcherRegistered = false; + + /** + * Constructor. + * @param GPhpThreadCriticalSection|null $criticalSection Instance of the critical section that is going to be associated with the created thread. Variable with null value is also valid. REFERENCE type. + * @param bool $allowThreadExitCodes Activates the support of thread exit codes. In that case the programmer needs to make sure that before the creation of a heavy thread there are no initialized objects whose destructors and particularly their multiple execution (in all the children and once in the parent) will affect the execution of the program in an undefined way. + */ + public function __construct(&$criticalSection, $allowThreadExitCodes) {// {{{ + if (GPhpThread::$seed === 0) { + self::$originPid = getmypid(); + } + $this->uniqueId = GPhpThread::$seed++; + $this->allowThreadExitCodes = $allowThreadExitCodes; + $this->criticalSection = &$criticalSection; + $this->parentPid = getmypid(); + } // }}} + + /** + * Destructor (default). It will not be called in the heavy thread if thread exit codes are disabled! + */ + public function __destruct() { // {{{ + } // }}} + + /** + * Resets the internal thread id generator. This can be used to allow creation of threads from another thread. + * + * Not recommended to be used especially in a more complex cases. + * @return void + */ + public static function resetThreadIdGenerator() { + self::$seed = 0; + } + + /** + * Execution protector. Recommended to be used everywhere where execution is not desired. + * For e.g. destructors which should be executed only in the master process. + * Indicates whether the place from which this method is called is a heavy thread or not. + * + * Can be used in 2 different ways. A direct way where the supplied parameter points to NULL. + * In this case the result is immediately returned, but the user will not be able to ignore + * the effect in any "inner" threads without using resetThreadIdGenerator() method which on the + * other hand will affect any previously created object instances (before the thread was launched (forked)). + * + * The other way is by subscribing a variable (most useful when is done in the constructor of your + * affected class). When subscribed initially its value will be set to false, but it will be + * updated after any calls to start()/stop(). + * + * @throws \GPhpThreadException If the supplied parameter is not of a GPhpThreadNotCloneableContainer or NULL type. + * @param null|\GPhpThreadNotCloneableContainer $isInsideGPhpThread A REFERENCE type. If it's set to null, the function will immediately return the result. Otherwise the variable will be subscribed for the result during the program's execution and its initial value will be set to false. + * @return null|bool Null if a variable is subscribed for the result. Else if the method caller is part ot a heavy thread returns true otherwise false. + */ + public static function isInGPhpThread(&$isInsideGPhpThread) { // {{{ + if ($isInsideGPhpThread === NULL) { + return self::$seed !== 0 && self::$originPid !== 0 && self::$originPid !== getmypid(); + } + if (!($isInsideGPhpThread instanceof \GPhpThreadNotCloneableContainer)) { + throw new \GPhpThreadException("Not supported parameter type - must be NULL or GPhpThreadNotCloneableContainer"); + } + $isInsideGPhpThread->import(false); + self::$originDynamicDataArr[((string)$isInsideGPhpThread)] = $isInsideGPhpThread; + return NULL; + } // }}} + + /** + * Specifies the running thread's exit code when it terminates. + * @param int $exitCode The exit code with which the thread will quit. + * @return void + */ + protected final function setExitCode($exitCode) { // {{{ + $this->exitCode = $exitCode; + } // }}} + + /** + * Returns the thread's exit code. + * @return int + */ + public final function getExitCode() { // {{{ + return $this->exitCode; + } // }}} + + /** + * Marks the start of a code block with high execution priority. + * @return void + */ + public static final function BGN_HIGH_PRIOR_EXEC_BLOCK() { + GPhpThread::$isCriticalSectionDispatcherRegistered = true; + unregister_tick_function('GPhpThreadCriticalSection::dispatch'); + } + + /** + * Marks the end of a code block with high execution priority. + * @return void + */ + public static final function END_HIGH_PRIOR_EXEC_BLOCK() { + register_tick_function('GPhpThreadCriticalSection::dispatch'); + } + + /** + * Returns if the current process is a parent (has created thread). + * @return bool If it is a parent returns true otherwise returns false. + */ + private function amIParent() { // {{{ + return ($this->childPid === null || $this->childPid > 0 ? true : false); + } // }}} + + /** + * Notifies the parent of the current thread that the thread has exited. + * @return void + */ + private function notifyParentThatChildIsTerminated() { // {{{ + posix_kill($this->parentPid, SIGCHLD); + } // }}} + + /** + * Returns the current thread's (process) id. + * @return int|bool On success returns a number different than 0. Otherwise returns false. + */ + public function getPid() { // {{{ + if ($this->amIParent()) { // I am parent + if ($this->amIStarted) return $this->childPid; + else return false; + } + return $this->_childPid; // I am child + } // }}} + + /** + * Sets the execution priority of the thread. A super user privileges are required. + * @param int $priority The priority number in the interval [-20; 20] where the lower value means higher priority. + * @return bool Returns true on success otherwise returns false. + */ + public function setPriority($priority) { // {{{ super user privileges required + if (!is_numeric($priority)) return false; + if ($this->amIParent()) { // I am parent + if ($this->amIStarted) + return @pcntl_setpriority($priority, $this->childPid, PRIO_PROCESS); + else return false; + } + + return @pcntl_setpriority($priority, $this->_childPid, PRIO_PROCESS); // I am child + } // }}} + + /** + * Returns the current execution priority of the thread. + * @return int|bool On success the priority number in the interval [-20; 20] where the lower value means higher priority. On failure returns false. + */ + public function getPriority() { // {{{ + if ($this->amIParent()) { // I am parent + if ($this->amIStarted) + return @pcntl_getpriority($this->childPid, PRIO_PROCESS); + else return false; + } + + return @pcntl_getpriority($this->_childPid, PRIO_PROCESS); // I am child + } // }}} + + /** + * Checks if the thread is alive. + * @return bool Returns true if the thread is alive otherwise returns false. + */ + public function isAlive() { // {{{ + return ($this->getPriority() !== false); + } // }}} + + /** + * Checks if the creator of the heavy thread is alive. + * @return bool Returns true if the parent is alive otherwise returns false. + */ + public function isParentAlive() { // {{{ + return @pcntl_getpriority(@posix_getppid(), PRIO_PROCESS) !== false; + } // }}} + + /** + * Suspends the thread execution for a specific amount of time, redirecting the CPU resources to somewhere else. The total delay is the sum of all passed parameters. + * @param int $microseconds The delay in microseconds. + * @param int $seconds (optional) The delay in seconds. + * @see \GPhpThread::milliSleep() Another similar method is milliSleep(). + * @return bool Returns true after all of the specified delay time elapsed. If the sleep was interrupted returns false. + */ + protected function sleep($microseconds, $seconds = 0) { // {{{ + if ($this->amIParent()) return false; + $microtime = microtime(true); + usleep($microseconds + ($seconds * 1000000)); + $elapsedMicrotime = microtime(true); + + if (($elapsedMicrotime - ($microseconds + ($seconds * 1000000))) >= $microtime) // the sleep was not interrupted + return true; + return false; + } // }}} + + /** + * Suspends the thread execution for a specific amount of milliseconds, redirecting the CPU resources to somewhere else. + * @param int $milliseconds The delay in milliseconds. + * @see \GPhpThread::sleep() Another similar method is sleep(). + * @return bool Returns true after all of the specified delay time elapsed. If the sleep was interrupted returns false. + */ + protected function milliSleep($milliseconds) { // {{{ + return $this->sleep($milliseconds * 1000); + } // }}} + + /** + * At process level decreases the niceness of a heavy "thread" making its priority higher. Multiple calls of the method will accumulate and increase the effect. + * @see \GPhpThread::makeUnfriendlier() A method with the opposite effect is GPhpThread::makeUnfriendlier(). + * @return bool Returns true on success or false in case of error or lack of privileges. + */ + protected function makeNicer() { // {{{ increases the priority + if ($this->amIParent()) return false; + return proc_nice(-1); + } // }}} + + /** + * At process level increases the niceness of a heavy "thread" making its priority lower. Multiple calls of the method will accumulate and increase the effect. + * @see \GPhpThread::makeNicer() A method with the opposite effect is GPhpThread::makeNicer(). + * @return bool Returns true on success or false in case of error or lack of privileges. + */ + protected function makeUnfriendlier() { // {{{ decreases the priority + if ($this->amIParent()) return false; + return proc_nice(1); + } // }}} + + /** + * Abstract method, the entry point of a particular GPhpThread inheritor implementation. + * @return void + */ + abstract public function run(); + + /** + * Starts the thread. + * @return bool On successful execution returns true otherwise returns false. + */ + public final function start() { // {{{ + if (!$this->amIParent()) return false; + if ($this->amIStarted) return false; + + $this->childPid = pcntl_fork(); + if ($this->childPid == -1) return false; + $this->_childPid = getmypid(); + $this->amIStarted = true; + + $csInitializationResult = null; + if ($this->criticalSection !== null) { + $csInitializationResult = $this->criticalSection->initialize($this->childPid, $this->uniqueId); + } + + if (!$this->amIParent()) { // child + // no dispatchers needed in the children; this means that no threads withing threads creation is possible + unregister_tick_function('GPhpThreadCriticalSection::dispatch'); + + // flag any subscribed variables indicating that the current + // instance is located in a GPhpThread + foreach (self::$originDynamicDataArr as &$o) { + if ($o instanceof \GPhpThreadNotCloneableContainer) { + $o->import(true); + } + } + + if ($csInitializationResult === false) $this->stop(); // don't execute the thread body if critical section is required, but missing + + pcntl_sigprocmask(SIG_UNBLOCK, array(SIGCHLD)); + $this->run(); + if ($this->criticalSection !== null) $this->notifyParentThatChildIsTerminated(); + $this->stop(); + } else { // parent + if ($this->childPid != -1 && $this->criticalSection !== null) { + + if ($csInitializationResult === false) { // don't add the thread to the dispatch queue if missing but required critical section is the case (actually this is done in the initialize method above) + $this->childPid = -1; + $this->_childPid = null; + $this->amIStarted = false; + return false; + } + + if (!GPhpThread::$isCriticalSectionDispatcherRegistered) + GPhpThread::$isCriticalSectionDispatcherRegistered = register_tick_function('GPhpThreadCriticalSection::dispatch'); + + pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD)); // SIGCHLD will wait in the queue until it's processed + } + return true; + } + return true; + } // }}} + + /** + * Stops executing thread. + * @param bool $force If it is set to true if performs forced stop (termination). + * @return bool True if the stop request was sent successfully otherwise false. + */ + public final function stop($force = false) { // {{{ + if (!$this->amIStarted) return false; + if ($this->amIParent() && $this->childPid !== null) { // parent + $r = posix_kill($this->childPid, ($force == false ? 15 : 9)); + if ($r) { + if ($this->join()) $this->childPid = null; + if ($this->criticalSection !== null) + $this->criticalSection->finalize($this->uniqueId); + $this->amIStarted = false; + } + return $r; + } + // child + if ($this->childPid == -1) return false; + + // Manually nullify all contained in this instance objects + // so hopefully their destructors will be called + $vars = get_object_vars($this); + foreach ($vars as &$v) { + if (is_object($v) || is_array($v)) { + $v = null; + } + } + + if (!$this->allowThreadExitCodes) { + // prevent the execution on any object's destructors + for ($i = 0; $i < 60; ++$i) { + posix_kill($this->getPid(), 9); + $this->sleep(0, 1); + } + } + exit((int)$this->getExitCode()); + } // }}} + + /** + * Waits for executing thread to return. + * @param bool $useBlocking If is set to true will block the until the thread returns. + * @return bool True if the thread has joined otherwise false. + */ + public final function join($useBlocking = true) { // {{{ + if (!$this->amIStarted) return false; + if ($this->amIParent()) { + $status = null; + $res = 0; + if ($useBlocking) { + GPhpThread::BGN_HIGH_PRIOR_EXEC_BLOCK(); + + while (($res = pcntl_waitpid($this->childPid, $status, WNOHANG)) == 0) { + GPhpThreadCriticalSection::dispatch(); + usleep(mt_rand(10000, 40000)); + } + + if ($res > 0 && pcntl_wifexited($status)) $this->exitCode = pcntl_wexitstatus($status); + else $this->exitCode = false; + + if ($this->criticalSection !== null) $this->criticalSection->finalize($this->uniqueId); + $this->childPid = null; + $this->_childPid = null; + $this->amIStarted = false; + + GPhpThread::END_HIGH_PRIOR_EXEC_BLOCK(); + } else { + $res = pcntl_waitpid($this->childPid, $status, WNOHANG); + if ($res > 0 && $this->criticalSection !== null) $this->criticalSection->finalize($this->uniqueId); + if ($res > 0 && pcntl_wifexited($status)) { + $this->exitCode = pcntl_wexitstatus($status); + if ($this->criticalSection !== null) $this->criticalSection->finalize($this->uniqueId); + $this->amIStarted = false; + } else if ($res == -1) { + $this->exitCode = false; + } + + if ($res != 0) { + if ($this->criticalSection !== null) $this->criticalSection->finalize($this->uniqueId); + $this->childPid = null; + $this->_childPid = null; + } + } + return $res; + } + if ($this->childPid == -1) return false; + exit(255); + } // }}} + + /** + * Pauses the execution of the thread. + * @return bool True if the pause request was successfully sent otherwise false. + */ + public final function pause() { // {{{ + if (!$this->amIParent() || !$this->amIStarted) return false; + return posix_kill($this->childPid, SIGSTOP); + } // }}} + + /** + * Resumes the execution of a paused thread. + * @return bool True if the execution resume request was successfully sent otherwise false. + */ + public final function resume() { // {{{ + if (!$this->amIParent() || !$this->amIStarted) return false; + return posix_kill($this->childPid, SIGCONT); + } // }}} +} // }}} +?> diff --git a/files/gphpthread.html b/files/gphpthread.html new file mode 100644 index 0000000..adb4fbb --- /dev/null +++ b/files/gphpthread.html @@ -0,0 +1,312 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
              +

              GPhpThread - a heavy threads implementation in pure PHP - Documentation

              + + + + + +
              + +
              +
              + + + + +
              +
              + + +
              +

              GPhpThread.php

              + +

              The MIT License (MIT)

              + +

              Copyright (c) 2024 zhgzhg

              +

              Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

              +

              The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

              +

              THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

              +
              + + +
              + Tags + + +
              +
              +
              + author +
              +
              + +

              zhgzhg @ github.com

              +
              + +
              +
              + version +
              +
              + 1.0.5 + + +
              +
              + copyright +
              +
              + +

              zhgzhg, 2024

              +
              + +
              +
              + + + +

              + Table of Contents + + +

              + + + + +

              + Classes + + +

              +
              +
              GPhpThreadException
              Exception thrown by GPhpThreads components
              GPhpThreadIntercom
              Process intercommunication class.
              GPhpThreadCriticalSection
              Critical section for sharing data between multiple processes.
              GPhpThreadNotCloneableContainer
              A data container not allowed to be cloned.
              GPhpThreadLockGuard
              A wrapper providing RAII mechanism for locking and unlocking +purposes of a critical section objects and a similar ones.
              GPhpThread
              A heavy thread creation and manipulation class.
              + + + + + + + + + + + + + +
              +
              +
              +
              +
              
              +        
              + +
              +
              + + + +
              +
              +
              + +
              + On this page + +
                +
              • Table Of Contents
              • +
              • + +
              • + + +
              +
              + +
              +
              +
              +
              +
              +

              Search results

              + +
              +
              +
                +
                +
                +
                +
                + + +
                + + + + + + + + diff --git a/graphs/classes.html b/graphs/classes.html new file mode 100644 index 0000000..ff78272 --- /dev/null +++ b/graphs/classes.html @@ -0,0 +1,104 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + +
                +

                GPhpThread - a heavy threads implementation in pure PHP - Documentation

                + + + + + +
                + +
                +
                + + + + +
                +
                + +
                + +
                +
                +
                +
                +

                Search results

                + +
                +
                +
                  +
                  +
                  +
                  +
                  + + +
                  + + + + + + + + diff --git a/graphs/classes.svg b/graphs/classes.svg new file mode 100644 index 0000000..2a7c563 --- /dev/null +++ b/graphs/classes.svg @@ -0,0 +1,59 @@ +GPhpThreadExceptionExceptionGPhpThreadIntercomGPhpThreadCriticalSectionGPhpThreadNotCloneableContainerSerializableGPhpThreadLockGuardGPhpThread \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..9361c24 --- /dev/null +++ b/index.html @@ -0,0 +1,147 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
                  +

                  GPhpThread - a heavy threads implementation in pure PHP - Documentation

                  + + + + + +
                  + +
                  +
                  + + + + +
                  +
                  +

                  Documentation

                  + + + +

                  + Table of Contents + + +

                  + +

                  + Packages + + +

                  +
                  +
                  Application
                  +
                  + + + +

                  + Classes + + +

                  +
                  +
                  GPhpThreadException
                  Exception thrown by GPhpThreads components
                  GPhpThreadIntercom
                  Process intercommunication class.
                  GPhpThreadCriticalSection
                  Critical section for sharing data between multiple processes.
                  GPhpThreadNotCloneableContainer
                  A data container not allowed to be cloned.
                  GPhpThreadLockGuard
                  A wrapper providing RAII mechanism for locking and unlocking +purposes of a critical section objects and a similar ones.
                  GPhpThread
                  A heavy thread creation and manipulation class.
                  + + + + + + + + + + + +
                  +
                  +
                  +
                  +
                  +

                  Search results

                  + +
                  +
                  +
                    +
                    +
                    +
                    +
                    + + +
                    + + + + + + + + diff --git a/indices/files.html b/indices/files.html new file mode 100644 index 0000000..eb70fa8 --- /dev/null +++ b/indices/files.html @@ -0,0 +1,113 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
                    +

                    GPhpThread - a heavy threads implementation in pure PHP - Documentation

                    + + + + + +
                    + +
                    +
                    + + + + +
                    +
                    + +

                    Files

                    +

                    G

                    + +
                    +
                    +
                    +
                    +
                    +

                    Search results

                    + +
                    +
                    +
                      +
                      +
                      +
                      +
                      + + +
                      + + + + + + + + diff --git a/js/search.js b/js/search.js new file mode 100644 index 0000000..093d6d0 --- /dev/null +++ b/js/search.js @@ -0,0 +1,173 @@ +// Search module for phpDocumentor +// +// This module is a wrapper around fuse.js that will use a given index and attach itself to a +// search form and to a search results pane identified by the following data attributes: +// +// 1. data-search-form +// 2. data-search-results +// +// The data-search-form is expected to have a single input element of type 'search' that will trigger searching for +// a series of results, were the data-search-results pane is expected to have a direct UL child that will be populated +// with rendered results. +// +// The search has various stages, upon loading this stage the data-search-form receives the CSS class +// 'phpdocumentor-search--enabled'; this indicates that JS is allowed and indices are being loaded. It is recommended +// to hide the form by default and show it when it receives this class to achieve progressive enhancement for this +// feature. +// +// After loading this module, it is expected to load a search index asynchronously, for example: +// +// +// +// In this script the generated index should attach itself to the search module using the `appendIndex` function. By +// doing it like this the page will continue loading, unhindered by the loading of the search. +// +// After the page has fully loaded, and all these deferred indexes loaded, the initialization of the search module will +// be called and the form will receive the class 'phpdocumentor-search--active', indicating search is ready. At this +// point, the input field will also have it's 'disabled' attribute removed. +var Search = (function () { + var fuse; + var index = []; + var options = { + shouldSort: true, + threshold: 0.6, + location: 0, + distance: 100, + maxPatternLength: 32, + minMatchCharLength: 1, + keys: [ + "fqsen", + "name", + "summary", + "url" + ] + }; + + // Credit David Walsh (https://davidwalsh.name/javascript-debounce-function) + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + function debounce(func, wait, immediate) { + var timeout; + + return function executedFunction() { + var context = this; + var args = arguments; + + var later = function () { + timeout = null; + if (!immediate) func.apply(context, args); + }; + + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + } + + function close() { + // Start scroll prevention: https://css-tricks.com/prevent-page-scrolling-when-a-modal-is-open/ + const scrollY = document.body.style.top; + document.body.style.position = ''; + document.body.style.top = ''; + window.scrollTo(0, parseInt(scrollY || '0') * -1); + // End scroll prevention + + var form = document.querySelector('[data-search-form]'); + var searchResults = document.querySelector('[data-search-results]'); + + form.classList.toggle('phpdocumentor-search--has-results', false); + searchResults.classList.add('phpdocumentor-search-results--hidden'); + var searchField = document.querySelector('[data-search-form] input[type="search"]'); + searchField.blur(); + } + + function search(event) { + // Start scroll prevention: https://css-tricks.com/prevent-page-scrolling-when-a-modal-is-open/ + document.body.style.position = 'fixed'; + document.body.style.top = `-${window.scrollY}px`; + // End scroll prevention + + // prevent enter's from autosubmitting + event.stopPropagation(); + + var form = document.querySelector('[data-search-form]'); + var searchResults = document.querySelector('[data-search-results]'); + var searchResultEntries = document.querySelector('[data-search-results] .phpdocumentor-search-results__entries'); + + searchResultEntries.innerHTML = ''; + + if (!event.target.value) { + close(); + return; + } + + form.classList.toggle('phpdocumentor-search--has-results', true); + searchResults.classList.remove('phpdocumentor-search-results--hidden'); + var results = fuse.search(event.target.value, {limit: 25}); + + results.forEach(function (result) { + var entry = document.createElement("li"); + entry.classList.add("phpdocumentor-search-results__entry"); + entry.innerHTML += '

                      ' + result.name + "

                      \n"; + entry.innerHTML += '' + result.fqsen + "\n"; + entry.innerHTML += '
                      ' + result.summary + '
                      '; + searchResultEntries.appendChild(entry) + }); + } + + function appendIndex(added) { + index = index.concat(added); + + // re-initialize search engine when appending an index after initialisation + if (typeof fuse !== 'undefined') { + fuse = new Fuse(index, options); + } + } + + function init() { + fuse = new Fuse(index, options); + + var form = document.querySelector('[data-search-form]'); + var searchField = document.querySelector('[data-search-form] input[type="search"]'); + + var closeButton = document.querySelector('.phpdocumentor-search-results__close'); + closeButton.addEventListener('click', function() { close() }.bind(this)); + + var searchResults = document.querySelector('[data-search-results]'); + searchResults.addEventListener('click', function() { close() }.bind(this)); + + form.classList.add('phpdocumentor-search--active'); + + searchField.setAttribute('placeholder', 'Search (Press "/" to focus)'); + searchField.removeAttribute('disabled'); + searchField.addEventListener('keyup', debounce(search, 300)); + + window.addEventListener('keyup', function (event) { + if (event.key === '/') { + searchField.focus(); + } + if (event.code === 'Escape') { + close(); + } + }.bind(this)); + } + + return { + appendIndex, + init + } +})(); + +window.addEventListener('DOMContentLoaded', function () { + var form = document.querySelector('[data-search-form]'); + + // When JS is supported; show search box. Must be before including the search for it to take effect immediately + form.classList.add('phpdocumentor-search--enabled'); +}); + +window.addEventListener('load', function () { + Search.init(); +}); diff --git a/js/searchIndex.js b/js/searchIndex.js new file mode 100644 index 0000000..68d807e --- /dev/null +++ b/js/searchIndex.js @@ -0,0 +1,414 @@ +Search.appendIndex( + [ + { + "fqsen": "\\GPhpThreadException", + "name": "GPhpThreadException", + "summary": "Exception\u0020thrown\u0020by\u0020GPhpThreads\u0020components", + "url": "classes/GPhpThreadException.html" + }, { + "fqsen": "\\GPhpThreadException\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Constructor.", + "url": "classes/GPhpThreadException.html#method___construct" + }, { + "fqsen": "\\GPhpThreadIntercom", + "name": "GPhpThreadIntercom", + "summary": "Process\u0020intercommunication\u0020class.", + "url": "classes/GPhpThreadIntercom.html" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Constructor.", + "url": "classes/GPhpThreadIntercom.html#method___construct" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003AisInitialized\u0028\u0029", + "name": "isInitialized", + "summary": "Checks\u0020if\u0020the\u0020intercom\u0020is\u0020initialized\u0020and\u0020ready\u0020for\u0020use.", + "url": "classes/GPhpThreadIntercom.html#method_isInitialized" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003AgetAutoDeletionFlag\u0028\u0029", + "name": "getAutoDeletionFlag", + "summary": "Returns\u0020the\u0020state\u0020of\u0020the\u0020option\u0020automatic\u0020deletion\u0020of\u0020the\u0020pipe\u0020file.", + "url": "classes/GPhpThreadIntercom.html#method_getAutoDeletionFlag" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003AsetAutoDeletionFlag\u0028\u0029", + "name": "setAutoDeletionFlag", + "summary": "Sets\u0020the\u0020automatic\u0020deletion\u0020option\u0020for\u0020the\u0020pipe\u0020file\u0020during\u0020the\u0020destruction\u0020of\u0020current\u0020instance.", + "url": "classes/GPhpThreadIntercom.html#method_setAutoDeletionFlag" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003A__destruct\u0028\u0029", + "name": "__destruct", + "summary": "Destructor.\u0020May\u0020try\u0020automatically\u0020to\u0020delete\u0020the\u0020pipe\u0020file.", + "url": "classes/GPhpThreadIntercom.html#method___destruct" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003Asend\u0028\u0029", + "name": "send", + "summary": "Sends\u0020data\u0020through\u0020the\u0020intercom.", + "url": "classes/GPhpThreadIntercom.html#method_send" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003Areceive\u0028\u0029", + "name": "receive", + "summary": "Receives\u0020data\u0020from\u0020the\u0020intercom.", + "url": "classes/GPhpThreadIntercom.html#method_receive" + }, { + "fqsen": "\\GPhpThreadIntercom\u003A\u003AisReceivingDataAvailable\u0028\u0029", + "name": "isReceivingDataAvailable", + "summary": "Checks\u0020if\u0020there\u0020is\u0020pending\u0020data\u0020for\u0020receiving.", + "url": "classes/GPhpThreadIntercom.html#method_isReceivingDataAvailable" + }, { + "fqsen": "\\GPhpThreadCriticalSection", + "name": "GPhpThreadCriticalSection", + "summary": "Critical\u0020section\u0020for\u0020sharing\u0020data\u0020between\u0020multiple\u0020processes.", + "url": "classes/GPhpThreadCriticalSection.html" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Constructor.", + "url": "classes/GPhpThreadCriticalSection.html#method___construct" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003A__destruct\u0028\u0029", + "name": "__destruct", + "summary": "Destructor.", + "url": "classes/GPhpThreadCriticalSection.html#method___destruct" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003Ainitialize\u0028\u0029", + "name": "initialize", + "summary": "Initializes\u0020the\u0020critical\u0020section.", + "url": "classes/GPhpThreadCriticalSection.html#method_initialize" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AcleanPipeGarbage\u0028\u0029", + "name": "cleanPipeGarbage", + "summary": "Cleans\u0020pipe\u0020files\u0020garbage\u0020left\u0020from\u0020any\u0020ungracefully\u0020terminated\u0020instances.", + "url": "classes/GPhpThreadCriticalSection.html#method_cleanPipeGarbage" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003Afinalize\u0028\u0029", + "name": "finalize", + "summary": "Finalization\u0020of\u0020a\u0020thread\u0020instance\u0020that\u0020ended\u0020and\u0020soon\u0020will\u0020be\u0020destroyed.", + "url": "classes/GPhpThreadCriticalSection.html#method_finalize" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AdoIOwnIt\u0028\u0029", + "name": "doIOwnIt", + "summary": "Confirms\u0020if\u0020the\u0020current\u0020thread\u0020has\u0020the\u0020ownership\u0020of\u0020the\u0020critical\u0020section\u0020associated\u0020with\u0020it.", + "url": "classes/GPhpThreadCriticalSection.html#method_doIOwnIt" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AencodeMessage\u0028\u0029", + "name": "encodeMessage", + "summary": "Encodes\u0020data\u0020in\u0020a\u0020message\u0020that\u0020will\u0020be\u0020sent\u0020to\u0020the\u0020thread\u0020process\u0020dispatcher.", + "url": "classes/GPhpThreadCriticalSection.html#method_encodeMessage" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AdecodeMessage\u0028\u0029", + "name": "decodeMessage", + "summary": "Decodes\u0020encoded\u0020from\u0020GPhpThread\u0027s\u0020instance\u0020message.", + "url": "classes/GPhpThreadCriticalSection.html#method_decodeMessage" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AisIntercomBroken\u0028\u0029", + "name": "isIntercomBroken", + "summary": "Checks\u0020if\u0020the\u0020internal\u0020intercom\u0020is\u0020broken.", + "url": "classes/GPhpThreadCriticalSection.html#method_isIntercomBroken" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003Asend\u0028\u0029", + "name": "send", + "summary": "Sends\u0020data\u0020operation\u0020to\u0020the\u0020main\u0020process\u0020dispatcher.", + "url": "classes/GPhpThreadCriticalSection.html#method_send" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003Areceive\u0028\u0029", + "name": "receive", + "summary": "Receives\u0020data\u0020operation\u0020from\u0020the\u0020main\u0020process\u0020dispatcher.", + "url": "classes/GPhpThreadCriticalSection.html#method_receive" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003ArequestLock\u0028\u0029", + "name": "requestLock", + "summary": "Tries\u0020to\u0020lock\u0020the\u0020critical\u0020section.", + "url": "classes/GPhpThreadCriticalSection.html#method_requestLock" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003ArequestUnlock\u0028\u0029", + "name": "requestUnlock", + "summary": "Tries\u0020to\u0020unlock\u0020the\u0020critical\u0020section.", + "url": "classes/GPhpThreadCriticalSection.html#method_requestUnlock" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AupdateDataContainer\u0028\u0029", + "name": "updateDataContainer", + "summary": "Executes\u0020data\u0020operation\u0020on\u0020the\u0020internal\u0020shared\u0020data\u0020container.", + "url": "classes/GPhpThreadCriticalSection.html#method_updateDataContainer" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AisPidAlive\u0028\u0029", + "name": "isPidAlive", + "summary": "Checks\u0020if\u0020specific\u0020process\u0020id\u0020is\u0020still\u0020alive.", + "url": "classes/GPhpThreadCriticalSection.html#method_isPidAlive" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AsortByLockAndDispatchPriority\u0028\u0029", + "name": "sortByLockAndDispatchPriority", + "summary": "Sort\u0020by\u0020occurred\u0020lock\u0020and\u0020dispatch\u0020priority.\u0020This\u0020is\u0020a\u0020workaround\nmethod\u0020required\u0020for\u0020PHP\u00205.3\u0020and\u0020relies\u0020on\u0020an\u0020initialized\n\u0024bindVariable\u0020inside\u0020this\u0020class.", + "url": "classes/GPhpThreadCriticalSection.html#method_sortByLockAndDispatchPriority" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AsortByLockDispatchPriorityAndMostThreadsInside\u0028\u0029", + "name": "sortByLockDispatchPriorityAndMostThreadsInside", + "summary": "Sort\u0020by\u0020occurred\u0020lock,\u0020dispatch\u0020priority\u0020and\u0020most\u0020threads\u0020using\nthe\u0020critical\u0020section.\u0020This\u0020is\u0020workaround\u0020method\u0020required\u0020for\nPHP\u00205.3\u0020and\u0020relies\u0020on\u0020an\u0020initialized\u0020\u0024bindVariable\u0020inside\u0020this\nclass.", + "url": "classes/GPhpThreadCriticalSection.html#method_sortByLockDispatchPriorityAndMostThreadsInside" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003Adispatch\u0028\u0029", + "name": "dispatch", + "summary": "Dispatcher\u0020responsible\u0020for\u0020the\u0020thread\u0020intercommunication\u0020and\u0020communication\u0020with\u0020their\u0020parent\u0020process.", + "url": "classes/GPhpThreadCriticalSection.html#method_dispatch" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AdataDispatch\u0028\u0029", + "name": "dataDispatch", + "summary": "Operations\u0020on\u0020the\u0020transferred\u0020data\u0020dispatch\u0020helper.", + "url": "classes/GPhpThreadCriticalSection.html#method_dataDispatch" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003Alock\u0028\u0029", + "name": "lock", + "summary": "Tries\u0020to\u0020lock\u0020the\u0020associated\u0020with\u0020the\u0020instance\u0020critical\u0020section.", + "url": "classes/GPhpThreadCriticalSection.html#method_lock" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003Aunlock\u0028\u0029", + "name": "unlock", + "summary": "Tries\u0020to\u0020unlock\u0020the\u0020associated\u0020with\u0020the\u0020instance\u0020critical\u0020section.", + "url": "classes/GPhpThreadCriticalSection.html#method_unlock" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AaddOrUpdateResource\u0028\u0029", + "name": "addOrUpdateResource", + "summary": "Adds\u0020or\u0020updates\u0020shared\u0020resource\u0020in\u0020a\u0020reliable,\u0020slower\u0020way.\u0020A\u0020lock\u0020of\u0020the\u0020critical\u0020section\u0020is\u0020required.", + "url": "classes/GPhpThreadCriticalSection.html#method_addOrUpdateResource" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AaddOrUpdateUnrelResource\u0028\u0029", + "name": "addOrUpdateUnrelResource", + "summary": "Adds\u0020or\u0020updates\u0020shared\u0020resource\u0020in\u0020an\u0020unreliable,\u0020faster\u0020way.\u0020A\u0020lock\u0020of\u0020the\u0020critical\u0020section\u0020is\u0020NOT\u0020required.", + "url": "classes/GPhpThreadCriticalSection.html#method_addOrUpdateUnrelResource" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AremoveResource\u0028\u0029", + "name": "removeResource", + "summary": "Removes\u0020shared\u0020resource\u0020in\u0020a\u0020reliable,\u0020slower\u0020way.\u0020A\u0020lock\u0020of\u0020the\u0020critical\u0020section\u0020is\u0020required.", + "url": "classes/GPhpThreadCriticalSection.html#method_removeResource" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AremoveUnrelResource\u0028\u0029", + "name": "removeUnrelResource", + "summary": "Removes\u0020shared\u0020resource\u0020in\u0020an\u0020unreliable,\u0020faster\u0020way.\u0020A\u0020lock\u0020of\u0020the\u0020critical\u0020section\u0020is\u0020NOT\u0020required.", + "url": "classes/GPhpThreadCriticalSection.html#method_removeUnrelResource" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AgetResourceValueFast\u0028\u0029", + "name": "getResourceValueFast", + "summary": "Returns\u0020an\u0020reliable\u0020resource\u0020without\u0020trying\u0020to\u0020ask\u0020for\u0020it\u0020the\u0020dispatcher.", + "url": "classes/GPhpThreadCriticalSection.html#method_getResourceValueFast" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AgetUnrelResourceValueFast\u0028\u0029", + "name": "getUnrelResourceValueFast", + "summary": "Returns\u0020an\u0020unreliable\u0020resource\u0020without\u0020trying\u0020to\u0020ask\u0020for\u0020it\u0020the\u0020dispatcher.", + "url": "classes/GPhpThreadCriticalSection.html#method_getUnrelResourceValueFast" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AgetResourceValue\u0028\u0029", + "name": "getResourceValue", + "summary": "Returns\u0020an\u0020reliable\u0020resource\u0020value\u0020by\u0020asking\u0020the\u0020dispatcher\u0020for\u0020it.\u0020An\u0020ownership\u0020of\u0020the\u0020critical\u0020section\u0020is\u0020required.", + "url": "classes/GPhpThreadCriticalSection.html#method_getResourceValue" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AgetUnrelResourceValue\u0028\u0029", + "name": "getUnrelResourceValue", + "summary": "Returns\u0020an\u0020unreliable\u0020resource\u0020value\u0020by\u0020asking\u0020the\u0020dispatcher\u0020for\u0020it.\u0020An\u0020ownership\u0020of\u0020the\u0020critical\u0020section\u0020is\u0020required.", + "url": "classes/GPhpThreadCriticalSection.html#method_getUnrelResourceValue" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AgetResourceNames\u0028\u0029", + "name": "getResourceNames", + "summary": "Returns\u0020the\u0020names\u0020of\u0020all\u0020reliable\u0020shared\u0020resources.", + "url": "classes/GPhpThreadCriticalSection.html#method_getResourceNames" + }, { + "fqsen": "\\GPhpThreadCriticalSection\u003A\u003AgetUnrelResourceNames\u0028\u0029", + "name": "getUnrelResourceNames", + "summary": "Returns\u0020the\u0020names\u0020of\u0020all\u0020unreliable\u0020shared\u0020resources.", + "url": "classes/GPhpThreadCriticalSection.html#method_getUnrelResourceNames" + }, { + "fqsen": "\\GPhpThreadNotCloneableContainer", + "name": "GPhpThreadNotCloneableContainer", + "summary": "A\u0020data\u0020container\u0020not\u0020allowed\u0020to\u0020be\u0020cloned.", + "url": "classes/GPhpThreadNotCloneableContainer.html" + }, { + "fqsen": "\\GPhpThreadNotCloneableContainer\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Constructor.", + "url": "classes/GPhpThreadNotCloneableContainer.html#method___construct" + }, { + "fqsen": "\\GPhpThreadNotCloneableContainer\u003A\u003A__toString\u0028\u0029", + "name": "__toString", + "summary": "Generates\u0020object\u0020id.", + "url": "classes/GPhpThreadNotCloneableContainer.html#method___toString" + }, { + "fqsen": "\\GPhpThreadNotCloneableContainer\u003A\u003Aimport\u0028\u0029", + "name": "import", + "summary": "Sets\u0020the\u0020value\u0020desired\u0020to\u0020be\u0020held.", + "url": "classes/GPhpThreadNotCloneableContainer.html#method_import" + }, { + "fqsen": "\\GPhpThreadNotCloneableContainer\u003A\u003Aexport\u0028\u0029", + "name": "export", + "summary": "Returns\u0020the\u0020contained\u0020value.", + "url": "classes/GPhpThreadNotCloneableContainer.html#method_export" + }, { + "fqsen": "\\GPhpThreadNotCloneableContainer\u003A\u003A\u0024variable", + "name": "variable", + "summary": "", + "url": "classes/GPhpThreadNotCloneableContainer.html#property_variable" + }, { + "fqsen": "\\GPhpThreadLockGuard", + "name": "GPhpThreadLockGuard", + "summary": "A\u0020wrapper\u0020providing\u0020RAII\u0020mechanism\u0020for\u0020locking\u0020and\u0020unlocking\npurposes\u0020of\u0020a\u0020critical\u0020section\u0020objects\u0020and\u0020a\u0020similar\u0020ones.", + "url": "classes/GPhpThreadLockGuard.html" + }, { + "fqsen": "\\GPhpThreadLockGuard\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Constructor.\u0020Immediately\u0020locks\u0020the\u0020passed\u0020critical\u0020section.", + "url": "classes/GPhpThreadLockGuard.html#method___construct" + }, { + "fqsen": "\\GPhpThreadLockGuard\u003A\u003A__destruct\u0028\u0029", + "name": "__destruct", + "summary": "Destructor.\u0020Immediately\u0020unlocks\u0020the\u0020passed\u0020critical\u0020section.", + "url": "classes/GPhpThreadLockGuard.html#method___destruct" + }, { + "fqsen": "\\GPhpThreadLockGuard\u003A\u003A\u0024criticalSectionObj", + "name": "criticalSectionObj", + "summary": "", + "url": "classes/GPhpThreadLockGuard.html#property_criticalSectionObj" + }, { + "fqsen": "\\GPhpThreadLockGuard\u003A\u003A\u0024unlockMethod", + "name": "unlockMethod", + "summary": "", + "url": "classes/GPhpThreadLockGuard.html#property_unlockMethod" + }, { + "fqsen": "\\GPhpThreadLockGuard\u003A\u003A\u0024unlockMethodsParams", + "name": "unlockMethodsParams", + "summary": "", + "url": "classes/GPhpThreadLockGuard.html#property_unlockMethodsParams" + }, { + "fqsen": "\\GPhpThread", + "name": "GPhpThread", + "summary": "A\u0020heavy\u0020thread\u0020creation\u0020and\u0020manipulation\u0020class.", + "url": "classes/GPhpThread.html" + }, { + "fqsen": "\\GPhpThread\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Constructor.", + "url": "classes/GPhpThread.html#method___construct" + }, { + "fqsen": "\\GPhpThread\u003A\u003A__destruct\u0028\u0029", + "name": "__destruct", + "summary": "Destructor\u0020\u0028default\u0029.\u0020It\u0020will\u0020not\u0020be\u0020called\u0020in\u0020the\u0020heavy\u0020thread\u0020if\u0020thread\u0020exit\u0020codes\u0020are\u0020disabled\u0021", + "url": "classes/GPhpThread.html#method___destruct" + }, { + "fqsen": "\\GPhpThread\u003A\u003AresetThreadIdGenerator\u0028\u0029", + "name": "resetThreadIdGenerator", + "summary": "Resets\u0020the\u0020internal\u0020thread\u0020id\u0020generator.\u0020This\u0020can\u0020be\u0020used\u0020to\u0020allow\u0020creation\u0020of\u0020threads\u0020from\u0020another\u0020thread.", + "url": "classes/GPhpThread.html#method_resetThreadIdGenerator" + }, { + "fqsen": "\\GPhpThread\u003A\u003AisInGPhpThread\u0028\u0029", + "name": "isInGPhpThread", + "summary": "Execution\u0020protector.\u0020Recommended\u0020to\u0020be\u0020used\u0020everywhere\u0020where\u0020execution\u0020is\u0020not\u0020desired.", + "url": "classes/GPhpThread.html#method_isInGPhpThread" + }, { + "fqsen": "\\GPhpThread\u003A\u003AsetExitCode\u0028\u0029", + "name": "setExitCode", + "summary": "Specifies\u0020the\u0020running\u0020thread\u0027s\u0020exit\u0020code\u0020when\u0020it\u0020terminates.", + "url": "classes/GPhpThread.html#method_setExitCode" + }, { + "fqsen": "\\GPhpThread\u003A\u003AgetExitCode\u0028\u0029", + "name": "getExitCode", + "summary": "Returns\u0020the\u0020thread\u0027s\u0020exit\u0020code.", + "url": "classes/GPhpThread.html#method_getExitCode" + }, { + "fqsen": "\\GPhpThread\u003A\u003ABGN_HIGH_PRIOR_EXEC_BLOCK\u0028\u0029", + "name": "BGN_HIGH_PRIOR_EXEC_BLOCK", + "summary": "Marks\u0020the\u0020start\u0020of\u0020a\u0020code\u0020block\u0020with\u0020high\u0020execution\u0020priority.", + "url": "classes/GPhpThread.html#method_BGN_HIGH_PRIOR_EXEC_BLOCK" + }, { + "fqsen": "\\GPhpThread\u003A\u003AEND_HIGH_PRIOR_EXEC_BLOCK\u0028\u0029", + "name": "END_HIGH_PRIOR_EXEC_BLOCK", + "summary": "Marks\u0020the\u0020end\u0020of\u0020a\u0020code\u0020block\u0020with\u0020high\u0020execution\u0020priority.", + "url": "classes/GPhpThread.html#method_END_HIGH_PRIOR_EXEC_BLOCK" + }, { + "fqsen": "\\GPhpThread\u003A\u003AamIParent\u0028\u0029", + "name": "amIParent", + "summary": "Returns\u0020if\u0020the\u0020current\u0020process\u0020is\u0020a\u0020parent\u0020\u0028has\u0020created\u0020thread\u0029.", + "url": "classes/GPhpThread.html#method_amIParent" + }, { + "fqsen": "\\GPhpThread\u003A\u003AnotifyParentThatChildIsTerminated\u0028\u0029", + "name": "notifyParentThatChildIsTerminated", + "summary": "Notifies\u0020the\u0020parent\u0020of\u0020the\u0020current\u0020thread\u0020that\u0020the\u0020thread\u0020has\u0020exited.", + "url": "classes/GPhpThread.html#method_notifyParentThatChildIsTerminated" + }, { + "fqsen": "\\GPhpThread\u003A\u003AgetPid\u0028\u0029", + "name": "getPid", + "summary": "Returns\u0020the\u0020current\u0020thread\u0027s\u0020\u0028process\u0029\u0020id.", + "url": "classes/GPhpThread.html#method_getPid" + }, { + "fqsen": "\\GPhpThread\u003A\u003AsetPriority\u0028\u0029", + "name": "setPriority", + "summary": "Sets\u0020the\u0020execution\u0020priority\u0020of\u0020the\u0020thread.\u0020A\u0020super\u0020user\u0020privileges\u0020are\u0020required.", + "url": "classes/GPhpThread.html#method_setPriority" + }, { + "fqsen": "\\GPhpThread\u003A\u003AgetPriority\u0028\u0029", + "name": "getPriority", + "summary": "Returns\u0020the\u0020current\u0020execution\u0020priority\u0020of\u0020the\u0020thread.", + "url": "classes/GPhpThread.html#method_getPriority" + }, { + "fqsen": "\\GPhpThread\u003A\u003AisAlive\u0028\u0029", + "name": "isAlive", + "summary": "Checks\u0020if\u0020the\u0020thread\u0020is\u0020alive.", + "url": "classes/GPhpThread.html#method_isAlive" + }, { + "fqsen": "\\GPhpThread\u003A\u003AisParentAlive\u0028\u0029", + "name": "isParentAlive", + "summary": "Checks\u0020if\u0020the\u0020creator\u0020of\u0020the\u0020heavy\u0020thread\u0020is\u0020alive.", + "url": "classes/GPhpThread.html#method_isParentAlive" + }, { + "fqsen": "\\GPhpThread\u003A\u003Asleep\u0028\u0029", + "name": "sleep", + "summary": "Suspends\u0020the\u0020thread\u0020execution\u0020for\u0020a\u0020specific\u0020amount\u0020of\u0020time,\u0020redirecting\u0020the\u0020CPU\u0020resources\u0020to\u0020somewhere\u0020else.\u0020The\u0020total\u0020delay\u0020is\u0020the\u0020sum\u0020of\u0020all\u0020passed\u0020parameters.", + "url": "classes/GPhpThread.html#method_sleep" + }, { + "fqsen": "\\GPhpThread\u003A\u003AmilliSleep\u0028\u0029", + "name": "milliSleep", + "summary": "Suspends\u0020the\u0020thread\u0020execution\u0020for\u0020a\u0020specific\u0020amount\u0020of\u0020milliseconds,\u0020redirecting\u0020the\u0020CPU\u0020resources\u0020to\u0020somewhere\u0020else.", + "url": "classes/GPhpThread.html#method_milliSleep" + }, { + "fqsen": "\\GPhpThread\u003A\u003AmakeNicer\u0028\u0029", + "name": "makeNicer", + "summary": "At\u0020process\u0020level\u0020decreases\u0020the\u0020niceness\u0020of\u0020a\u0020heavy\u0020\u0022thread\u0022\u0020making\u0020its\u0020priority\u0020higher.\u0020Multiple\u0020calls\u0020of\u0020the\u0020method\u0020will\u0020accumulate\u0020and\u0020increase\u0020the\u0020effect.", + "url": "classes/GPhpThread.html#method_makeNicer" + }, { + "fqsen": "\\GPhpThread\u003A\u003AmakeUnfriendlier\u0028\u0029", + "name": "makeUnfriendlier", + "summary": "At\u0020process\u0020level\u0020increases\u0020the\u0020niceness\u0020of\u0020a\u0020heavy\u0020\u0022thread\u0022\u0020making\u0020its\u0020priority\u0020lower.\u0020Multiple\u0020calls\u0020of\u0020the\u0020method\u0020will\u0020accumulate\u0020and\u0020increase\u0020the\u0020effect.", + "url": "classes/GPhpThread.html#method_makeUnfriendlier" + }, { + "fqsen": "\\GPhpThread\u003A\u003Arun\u0028\u0029", + "name": "run", + "summary": "Abstract\u0020method,\u0020the\u0020entry\u0020point\u0020of\u0020a\u0020particular\u0020GPhpThread\u0020inheritor\u0020implementation.", + "url": "classes/GPhpThread.html#method_run" + }, { + "fqsen": "\\GPhpThread\u003A\u003Astart\u0028\u0029", + "name": "start", + "summary": "Starts\u0020the\u0020thread.", + "url": "classes/GPhpThread.html#method_start" + }, { + "fqsen": "\\GPhpThread\u003A\u003Astop\u0028\u0029", + "name": "stop", + "summary": "Stops\u0020executing\u0020thread.", + "url": "classes/GPhpThread.html#method_stop" + }, { + "fqsen": "\\GPhpThread\u003A\u003Ajoin\u0028\u0029", + "name": "join", + "summary": "Waits\u0020for\u0020executing\u0020thread\u0020to\u0020return.", + "url": "classes/GPhpThread.html#method_join" + }, { + "fqsen": "\\GPhpThread\u003A\u003Apause\u0028\u0029", + "name": "pause", + "summary": "Pauses\u0020the\u0020execution\u0020of\u0020the\u0020thread.", + "url": "classes/GPhpThread.html#method_pause" + }, { + "fqsen": "\\GPhpThread\u003A\u003Aresume\u0028\u0029", + "name": "resume", + "summary": "Resumes\u0020the\u0020execution\u0020of\u0020a\u0020paused\u0020thread.", + "url": "classes/GPhpThread.html#method_resume" + }, { + "fqsen": "\\", + "name": "\\", + "summary": "", + "url": "namespaces/default.html" + } ] +); diff --git a/js/template.js b/js/template.js new file mode 100644 index 0000000..4938329 --- /dev/null +++ b/js/template.js @@ -0,0 +1,17 @@ +(function(){ + window.addEventListener('load', () => { + const el = document.querySelector('.phpdocumentor-on-this-page__content') + if (!el) { + return; + } + + const observer = new IntersectionObserver( + ([e]) => { + e.target.classList.toggle("-stuck", e.intersectionRatio < 1); + }, + {threshold: [1]} + ); + + observer.observe(el); + }) +})(); diff --git a/namespaces/default.html b/namespaces/default.html new file mode 100644 index 0000000..3b16d33 --- /dev/null +++ b/namespaces/default.html @@ -0,0 +1,253 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
                      +

                      GPhpThread - a heavy threads implementation in pure PHP - Documentation

                      + + + + + +
                      + +
                      +
                      + + + + +
                      +
                      +
                        +
                      + +
                      +

                      API Documentation

                      + + +

                      + Table of Contents + + +

                      + + + + +

                      + Classes + + +

                      +
                      +
                      GPhpThreadException
                      Exception thrown by GPhpThreads components
                      GPhpThreadIntercom
                      Process intercommunication class.
                      GPhpThreadCriticalSection
                      Critical section for sharing data between multiple processes.
                      GPhpThreadNotCloneableContainer
                      A data container not allowed to be cloned.
                      GPhpThreadLockGuard
                      A wrapper providing RAII mechanism for locking and unlocking +purposes of a critical section objects and a similar ones.
                      GPhpThread
                      A heavy thread creation and manipulation class.
                      + + + + + + + + + + + +
                      +
                      +
                      +
                      +
                      
                      +        
                      + +
                      +
                      + + + +
                      +
                      +
                      + +
                      + On this page + +
                        +
                      • Table Of Contents
                      • +
                      • + +
                      • + + +
                      +
                      + +
                      +
                      +
                      +
                      +
                      +

                      Search results

                      + +
                      +
                      +
                        +
                        +
                        +
                        +
                        + + +
                        + + + + + + + + diff --git a/packages/Application.html b/packages/Application.html new file mode 100644 index 0000000..48e74a2 --- /dev/null +++ b/packages/Application.html @@ -0,0 +1,253 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
                        +

                        GPhpThread - a heavy threads implementation in pure PHP - Documentation

                        + + + + + +
                        + +
                        +
                        + + + + +
                        +
                        +
                          +
                        + +
                        +

                        Application

                        + + +

                        + Table of Contents + + +

                        + + + + +

                        + Classes + + +

                        +
                        +
                        GPhpThreadException
                        Exception thrown by GPhpThreads components
                        GPhpThreadIntercom
                        Process intercommunication class.
                        GPhpThreadCriticalSection
                        Critical section for sharing data between multiple processes.
                        GPhpThreadNotCloneableContainer
                        A data container not allowed to be cloned.
                        GPhpThreadLockGuard
                        A wrapper providing RAII mechanism for locking and unlocking +purposes of a critical section objects and a similar ones.
                        GPhpThread
                        A heavy thread creation and manipulation class.
                        + + + + + + + + + + + +
                        +
                        +
                        +
                        +
                        
                        +        
                        + +
                        +
                        + + + +
                        +
                        +
                        + +
                        + On this page + +
                          +
                        • Table Of Contents
                        • +
                        • + +
                        • + + +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +

                        Search results

                        + +
                        +
                        +
                          +
                          +
                          +
                          +
                          + + +
                          + + + + + + + + diff --git a/packages/default.html b/packages/default.html new file mode 100644 index 0000000..f646237 --- /dev/null +++ b/packages/default.html @@ -0,0 +1,252 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation + + + + + + + + + + + + + + + + + + + + + +
                          +

                          GPhpThread - a heavy threads implementation in pure PHP - Documentation

                          + + + + + +
                          + +
                          +
                          + + + + +
                          +
                          +
                            +
                          + +
                          +

                          API Documentation

                          + + +

                          + Table of Contents + + +

                          + +

                          + Packages + + +

                          +
                          +
                          Application
                          +
                          + + + + + + + + + + + + + + +
                          +
                          +
                          +
                          +
                          
                          +        
                          + +
                          +
                          + + + +
                          +
                          +
                          + +
                          + On this page + +
                            +
                          • Table Of Contents
                          • +
                          • +
                              +
                            +
                          • + + +
                          +
                          + +
                          +
                          +
                          +
                          +
                          +

                          Search results

                          + +
                          +
                          +
                            +
                            +
                            +
                            +
                            + + +
                            + + + + + + + + diff --git a/reports/deprecated.html b/reports/deprecated.html new file mode 100644 index 0000000..afb1ef0 --- /dev/null +++ b/reports/deprecated.html @@ -0,0 +1,120 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation » Deprecated elements + + + + + + + + + + + + + + + + + + + + + + +
                            +

                            GPhpThread - a heavy threads implementation in pure PHP - Documentation

                            + + + + + +
                            + +
                            +
                            + + + + +
                            +
                            + + +
                            +

                            Deprecated

                            + + +
                            + No deprecated elements have been found in this project. +
                            +
                            +
                            +
                            +
                            +
                            +
                            +

                            Search results

                            + +
                            +
                            +
                              +
                              +
                              +
                              +
                              + + +
                              + + + + + + + + diff --git a/reports/errors.html b/reports/errors.html new file mode 100644 index 0000000..dfae16a --- /dev/null +++ b/reports/errors.html @@ -0,0 +1,119 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation » Compilation errors + + + + + + + + + + + + + + + + + + + + + + +
                              +

                              GPhpThread - a heavy threads implementation in pure PHP - Documentation

                              + + + + + +
                              + +
                              +
                              + + + + +
                              +
                              + + +
                              +

                              Errors

                              + + +
                              No errors have been found in this project.
                              + +
                              +
                              +
                              +
                              +
                              +
                              +

                              Search results

                              + +
                              +
                              +
                                +
                                +
                                +
                                +
                                + + +
                                + + + + + + + + diff --git a/reports/markers.html b/reports/markers.html new file mode 100644 index 0000000..b2b6e12 --- /dev/null +++ b/reports/markers.html @@ -0,0 +1,120 @@ + + + + + GPhpThread - a heavy threads implementation in pure PHP - Documentation » Markers + + + + + + + + + + + + + + + + + + + + + + +
                                +

                                GPhpThread - a heavy threads implementation in pure PHP - Documentation

                                + + + + + +
                                + +
                                +
                                + + + + +
                                +
                                + + +
                                +

                                Markers

                                + +
                                + No markers have been found in this project. +
                                + +
                                +
                                +
                                +
                                +
                                +
                                +

                                Search results

                                + +
                                +
                                +
                                  +
                                  +
                                  +
                                  +
                                  + + +
                                  + + + + + + + +