Advertisement
Guest User

Untitled

a guest
Aug 17th, 2018
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 4.51 KB | None | 0 0
  1. <?php
  2. class SystemCall {
  3.     protected $callback;
  4.  
  5.     public function __construct(callable $callback) {
  6.         $this->callback = $callback;
  7.     }
  8.  
  9.     public function __invoke(Task $task, Scheduler $scheduler) {
  10.         $callback = $this->callback;
  11.         return $callback($task, $scheduler);
  12.     }
  13. }
  14.  
  15. class Task {
  16.     protected $taskId;
  17.     protected $coroutine;
  18.     protected $sendValue = null;
  19.     protected $beforeFirstYield = true; // The first yield is implicitly called to
  20.                                         // determine that the value of the first
  21.                                         // yield can be returned correctly.
  22.  
  23.     public function __construct($taskId, Generator $coroutine) {
  24.         $this->taskId = $taskId;
  25.         $this->coroutine = $coroutine;
  26.     }
  27.  
  28.     public function getTaskId() {
  29.         return $this->taskId;
  30.     }
  31.  
  32.     public function setSendValue($sendValue) {
  33.         $this->sendValue = $sendValue;
  34.     }
  35.  
  36.     public function run() {
  37.         if ($this->beforeFirstYield) {
  38.             $this->beforeFirstYield = false;
  39.             return $this->coroutine->current(); //the first yield, see comment above.
  40.         } else {
  41.             $retval = $this->coroutine->send($this->sendValue); // the returned yield point
  42.             $this->sendValue = null;
  43.             return $retval;
  44.         }
  45.     }
  46.  
  47.     public function isFinished() {
  48.         return !$this->coroutine->valid();
  49.     }
  50. }
  51.  
  52. class Scheduler {
  53.     protected $maxTaskId = 0;
  54.     protected $taskMap = []; // taskId => task
  55.     protected $taskQueue;
  56.  
  57.     public function __construct() {
  58.         $this->taskQueue = new SplQueue();
  59.     }
  60.  
  61.     public function newTask(Generator $coroutine) {
  62.         $tid = ++$this->maxTaskId;
  63.         $task = new Task($tid, $coroutine);
  64.         $this->taskMap[$tid] = $task;
  65.         $this->schedule($task);
  66.         return $tid;
  67.     }
  68.  
  69.     public function schedule(Task $task) {
  70.         $this->taskQueue->enqueue($task);
  71.     }
  72.  
  73.     public function run() {
  74.         while (!$this->taskQueue->isEmpty()) {
  75.             $task = $this->taskQueue->dequeue();
  76.             $retval = $task->run();
  77.      
  78.             if ($retval instanceof SystemCall) {
  79.                 $retval($task, $this);
  80.                 continue;
  81.             }
  82.      
  83.             if ($task->isFinished()) {
  84.                 unset($this->taskMap[$task->getTaskId()]);
  85.             } else {
  86.                 $this->schedule($task);
  87.             }
  88.         }
  89.     }
  90.  
  91.     public function killTask($tid) {
  92.         if (!isset($this->taskMap[$tid])) {
  93.             return false;
  94.         }
  95.      
  96.         unset($this->taskMap[$tid]);
  97.      
  98.         // This is a bit ugly and could be optimized so it does not have to walk the queue,
  99.         // but assuming that killing tasks is rather rare I won't bother with it now
  100.         foreach ($this->taskQueue as $i => $task) {
  101.             if ($task->getTaskId() === $tid) {
  102.                 unset($this->taskQueue[$i]);
  103.                 break;
  104.             }
  105.         }
  106.      
  107.         return true;
  108.     }
  109. }
  110.  
  111. // generate a system call for a new task
  112. function newTask(Generator $coroutine) {
  113.     return new SystemCall(
  114.         function(Task $task, Scheduler $scheduler) use ($coroutine) {
  115.             $task->setSendValue($scheduler->newTask($coroutine));
  116.             $scheduler->schedule($task);
  117.         }
  118.     );
  119. }
  120.  
  121. // kill the current coroutine
  122. function killTask($tid) {
  123.     return new SystemCall(
  124.         function(Task $task, Scheduler $scheduler) use ($tid) {
  125.             $task->setSendValue($scheduler->killTask($tid));
  126.             $scheduler->schedule($task);
  127.         }
  128.     );
  129. }
  130.  
  131. // get the current task id
  132. function getTaskId() {
  133.     return new SystemCall(function(Task $task, Scheduler $scheduler) {
  134.         $task->setSendValue($task->getTaskId());
  135.         $scheduler->schedule($task);
  136.     });
  137. }
  138.  
  139.  
  140. /*
  141.  *
  142.  * fix engine here
  143.  *
  144.  */
  145.  
  146.  
  147.  
  148. function childTask() {
  149.     $myid = (yield getTaskId());
  150.     while (true) {
  151.         echo "Child task $myid still alive!\n";
  152.         yield;
  153.     }
  154. }
  155.  
  156. function task() {
  157.     $myid = (yield getTaskId());
  158.     echo "Parent task $myid boot.\n";
  159.    
  160.     $child1 = (yield newTask(childTask()));
  161.     $child2 = (yield newTask(childTask()));
  162.     $child3 = (yield newTask(childTask()));
  163.     $child4 = (yield newTask(childTask()));
  164.    
  165.    
  166.     for ($i = 0; $i < 20; $i++) {
  167.         echo "Parent task $myid iteration $i.\n";
  168.         yield;
  169.  
  170.         if ($i == 4) yield killTask($child1);
  171.         if ($i == 8) yield killTask($child2);
  172.         if ($i == 12) yield killTask($child3);
  173.         if ($i == 16) yield killTask($child4);
  174.     }
  175. }
  176.  
  177. $scheduler = new Scheduler;
  178. $scheduler->newTask(task());
  179. $scheduler->run();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement