Passed
Push — dev ( 50ea2d...f3696b )
by Janko
05:18
created

SemaphoreUtil::getSemaphore()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 14
ccs 0
cts 10
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Stu\Module\Control;
4
5
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Stu\Component\Game\SemaphoreConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Game\SemaphoreConstants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Stu\Exception\SemaphoreException;
8
use Stu\Module\Config\StuConfigInterface;
9
use Stu\Module\Logging\LogTypeEnum;
10
use Stu\Module\Logging\StuLogger;
11
use SysvSemaphore;
12
13
final class SemaphoreUtil implements SemaphoreUtilInterface
14
{
15
    /** @var array<int, SysvSemaphore> */
16
    public static array $semaphores = [];
17
18 2
    public function __construct(private readonly StuConfigInterface $stuConfig) {}
19
20 131
    #[Override]
21
    public function isSemaphoreAlreadyAcquired(int $key): bool
22
    {
23 131
        return array_key_exists($key, self::$semaphores);
24
    }
25
26 151
    #[Override]
27
    public function acquireSemaphore(int $key): null|int|SysvSemaphore
28
    {
29 151
        if (!$this->isSemaphoreUsageActive()) {
30 151
            return null;
31
        }
32
33
        $semaphore = $this->getSemaphore($key);
34
35
        if ($this->isSemaphoreAlreadyAcquired($key)) {
36
            return null;
37
        }
38
39
        $this->acquire($semaphore);
40
        self::$semaphores[$key] = $semaphore;
41
42
        return $semaphore;
43
    }
44
45
    private function getSemaphore(int $key): SysvSemaphore
46
    {
47
        $semaphore = sem_get(
48
            $key,
49
            1,
50
            0o666,
51
            SemaphoreConstants::AUTO_RELEASE_SEMAPHORES
52
        );
53
54
        if ($semaphore === false) {
55
            throw new SemaphoreException('Error getting semaphore');
56
        }
57
58
        return $semaphore;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $semaphore could return the type resource which is incompatible with the type-hinted return SysvSemaphore. Consider adding an additional type-check to rule them out.
Loading history...
59
    }
60
61
    private function acquire(SysvSemaphore $semaphore): void
62
    {
63
        if (!sem_acquire($semaphore)) {
64
            throw new SemaphoreException("Error acquiring Semaphore!");
65
        }
66
    }
67
68 151
    #[Override]
69
    public function releaseSemaphore(null|int|SysvSemaphore $semaphore, bool $doRemove = false): void
70
    {
71 151
        if (!$this->isSemaphoreUsageActive() || !$semaphore instanceof SysvSemaphore) {
72 151
            return;
73
        }
74
75
        $this->release($semaphore, $doRemove);
76
    }
77
78
    #[Override]
79
    public function releaseAllSemaphores(bool $doRemove = false): void
80
    {
81
        if (!$this->isSemaphoreUsageActive()) {
82
            return;
83
        }
84
85
        foreach (self::$semaphores as $semaphore) {
86
            $this->release($semaphore, $doRemove);
87
        }
88
    }
89
90
    private function release(SysvSemaphore $semaphore, bool $doRemove): void
91
    {
92
        $key = array_search($semaphore, self::$semaphores, true);
93
        if ($key === false) {
94
            return;
95
        }
96
        unset(self::$semaphores[$key]);
97
98
        if (!sem_release($semaphore)) {
99
            StuLogger::log(sprintf("Error releasing Semaphore with key %d!", $key), LogTypeEnum::SEMAPHORE);
100
            return;
101
            //throw new SemaphoreException("Error releasing Semaphore!");
102
        } else {
103
            StuLogger::logf('Released semaphore %d', $key);
104
        }
105
106
        if ($doRemove && !sem_remove($semaphore)) {
107
            StuLogger::log(sprintf("Error removing Semaphore with key %d!", $key), LogTypeEnum::SEMAPHORE);
108
            //throw new SemaphoreException("Error removing Semaphore!");
109
        }
110
    }
111
112 151
    private function isSemaphoreUsageActive(): bool
113
    {
114 151
        return $this->stuConfig->getGameSettings()->useSemaphores();
115
    }
116
117 7
    public static function reset(): void
118
    {
119 7
        self::$semaphores = [];
120
    }
121
}
122