PocketMine-MP 5.15.1 git-fb9a74e8799c71ed8292cfa53abe7a4c9204629d
Process.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\utils;
25
27use function count;
28use function exec;
29use function fclose;
30use function file;
31use function file_get_contents;
32use function function_exists;
33use function getmypid;
34use function getmyuid;
35use function hexdec;
36use function memory_get_usage;
37use function posix_kill;
38use function preg_match;
39use function proc_close;
40use function proc_open;
41use function str_starts_with;
42use function stream_get_contents;
43use function trim;
44
45final class Process{
46
47 private function __construct(){
48 //NOOP
49 }
50
55 public static function getAdvancedMemoryUsage(){
56 $reserved = memory_get_usage();
57 $VmSize = null;
58 $VmRSS = null;
59 if(Utils::getOS() === Utils::OS_LINUX || Utils::getOS() === Utils::OS_ANDROID){
60 $status = @file_get_contents("/proc/self/status");
61 if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible");
62
63 // the numbers found here should never be bigger than PHP_INT_MAX, so we expect them to always be castable to int
64 if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
65 $VmRSS = ((int) $matches[1]) * 1024;
66 }
67
68 if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
69 $VmSize = ((int) $matches[1]) * 1024;
70 }
71 }
72
73 //TODO: more OS
74
75 if($VmRSS === null){
76 $VmRSS = memory_get_usage();
77 }
78
79 if($VmSize === null){
80 $VmSize = memory_get_usage(true);
81 }
82
83 return [$reserved, $VmRSS, $VmSize];
84 }
85
86 public static function getMemoryUsage() : int{
87 return self::getAdvancedMemoryUsage()[1];
88 }
89
93 public static function getRealMemoryUsage() : array{
94 $stack = 0;
95 $heap = 0;
96
97 if(Utils::getOS() === Utils::OS_LINUX || Utils::getOS() === Utils::OS_ANDROID){
98 $mappings = @file("/proc/self/maps");
99 if($mappings === false) throw new AssumptionFailedError("/proc/self/maps should always be accessible");
100 foreach($mappings as $line){
101 if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){
102 if(str_starts_with($matches[3], "heap")){
103 $heap += (int) hexdec($matches[2]) - (int) hexdec($matches[1]);
104 }elseif(str_starts_with($matches[3], "stack")){
105 $stack += (int) hexdec($matches[2]) - (int) hexdec($matches[1]);
106 }
107 }
108 }
109 }
110
111 return [$heap, $stack];
112 }
113
114 public static function getThreadCount() : int{
115 if(Utils::getOS() === Utils::OS_LINUX || Utils::getOS() === Utils::OS_ANDROID){
116 $status = @file_get_contents("/proc/self/status");
117 if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible");
118 if(preg_match("/Threads:[ \t]+([0-9]+)/", $status, $matches) > 0){
119 return (int) $matches[1];
120 }
121 }
122
123 //TODO: more OS
124
125 return Thread::getRunningCount() + 1; //pmmpthread doesn't count the main thread
126 }
127
131 public static function kill(int $pid, bool $subprocesses = false) : void{
132 $logger = \GlobalLogger::get();
133 if($logger instanceof MainLogger){
134 $logger->syncFlushBuffer();
135 }
136 switch(Utils::getOS()){
137 case Utils::OS_WINDOWS:
138 exec("taskkill.exe /F " . ($subprocesses ? "/T " : "") . "/PID $pid > NUL 2> NUL");
139 break;
140 case Utils::OS_MACOS:
141 case Utils::OS_LINUX:
142 default:
143 if($subprocesses){
144 $pid = -$pid;
145 }
146 if(function_exists("posix_kill")){
147 posix_kill($pid, 9); //SIGKILL
148 }else{
149 exec("kill -9 $pid > /dev/null 2>&1");
150 }
151 }
152 }
153
163 public static function execute(string $command, ?string &$stdout = null, ?string &$stderr = null) : int{
164 $process = proc_open($command, [
165 ["pipe", "r"],
166 ["pipe", "w"],
167 ["pipe", "w"]
168 ], $pipes);
169
170 if($process === false){
171 $stderr = "Failed to open process";
172 $stdout = "";
173
174 return -1;
175 }
176
177 $stdout = stream_get_contents($pipes[1]);
178 $stderr = stream_get_contents($pipes[2]);
179
180 foreach($pipes as $p){
181 fclose($p);
182 }
183
184 return proc_close($process);
185 }
186
187 public static function pid() : int{
188 $result = getmypid();
189 if($result === false){
190 throw new \LogicException("getmypid() doesn't work on this platform");
191 }
192 return $result;
193 }
194
195 public static function uid() : int{
196 $result = getmyuid();
197 if($result === false){
198 throw new \LogicException("getmyuid() doesn't work on this platform");
199 }
200 return $result;
201 }
202}
static kill(int $pid, bool $subprocesses=false)
Definition: Process.php:131
static execute(string $command, ?string &$stdout=null, ?string &$stderr=null)
Definition: Process.php:163
static getRealMemoryUsage()
Definition: Process.php:93
static getAdvancedMemoryUsage()
Definition: Process.php:55
static getOS(bool $recalculate=false)
Definition: Utils.php:275