Unix.Processors.Mod 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. (* Unix runtime support for processors *)
  2. (* Copyright (C) Florian Negele *)
  3. MODULE Processors;
  4. IMPORT Unix;
  5. (** Indicates the maximal number of logical processors that are supported by the system. *)
  6. CONST Maximum* = MAX (SET) - MIN (SET) + 1;
  7. (** Holds the actual number of processors in the system. *)
  8. VAR count-: SIZE;
  9. VAR affinityMask: SET;
  10. VAR semaphore: Unix.Sem;
  11. VAR barrier: Unix.Barrier;
  12. VAR thread: ARRAY Maximum OF Unix.Thread_t;
  13. (** Returns the unique index of the processor executing this procedure call. *)
  14. PROCEDURE GetCurrentIndex- EXTERN "Activities.GetCurrentProcessorIndex" (): SIZE;
  15. (** Suspends the execution of the current processor. *)
  16. (** A suspended processor must be resumed by a call to the ResumeAnyProcessor procedure. *)
  17. PROCEDURE SuspendCurrentProcessor-;
  18. BEGIN {UNCOOPERATIVE, UNCHECKED}
  19. ASSERT (Unix.sem_wait (ADDRESS OF semaphore) = 0);
  20. END SuspendCurrentProcessor;
  21. (** Resumes the execution of all suspended processors. *)
  22. PROCEDURE ResumeAllProcessors-;
  23. BEGIN {UNCOOPERATIVE, UNCHECKED}
  24. ASSERT (Unix.sem_post (ADDRESS OF semaphore) = 0);
  25. END ResumeAllProcessors;
  26. (** Starts the execution of all available processors. *)
  27. PROCEDURE StartAll-;
  28. BEGIN {UNCOOPERATIVE, UNCHECKED}
  29. ASSERT (count > 1);
  30. IF Unix.pthread_barrier_wait (ADDRESS OF barrier) = Unix.PTHREAD_BARRIER_SERIAL_THREAD THEN
  31. ASSERT (Unix.pthread_barrier_destroy (ADDRESS OF barrier) = 0);
  32. END;
  33. END StartAll;
  34. (* Start routine for each Posix thread. *)
  35. PROCEDURE {C} Start (arg: ADDRESS): ADDRESS;
  36. PROCEDURE Execute EXTERN "Activities.Execute" (procedure: PROCEDURE);
  37. PROCEDURE Idle EXTERN "Activities.Idle";
  38. BEGIN {UNCOOPERATIVE, UNCHECKED}
  39. StartAll;
  40. Execute (Idle);
  41. RETURN NIL;
  42. END Start;
  43. (** Initializes the module by enumerating all available processors. *)
  44. (** The number of concurrent threads corresponds to the number of slots in the affinity mask of the current process. *)
  45. PROCEDURE Initialize-;
  46. VAR self: Unix.Thread_t; mask: SET; i: SIZE; length: WORD;
  47. BEGIN {UNCOOPERATIVE, UNCHECKED}
  48. self := Unix.pthread_self ();
  49. ASSERT (Unix.sem_init (ADDRESS OF semaphore, 0, 0) = 0);
  50. ASSERT (Unix.pthread_getaffinity_np (self, SIZE OF SET, ADDRESS OF affinityMask) = 0);
  51. length := 0; FOR i := 0 TO Maximum - 1 DO IF i IN affinityMask THEN INC (length) END END;
  52. ASSERT (Unix.pthread_barrier_init (ADDRESS OF barrier, NIL, length) = 0);
  53. count := 0;
  54. FOR i := 0 TO Maximum - 1 DO
  55. IF i IN affinityMask THEN
  56. INC (count);
  57. IF count = 1 THEN
  58. thread[i] := self;
  59. ELSE
  60. ASSERT (Unix.pthread_create (ADDRESS OF thread[i], NIL, Start, NIL) = 0);
  61. END;
  62. mask := {i};
  63. ASSERT (Unix.pthread_setaffinity_np (thread[i], SIZE OF SET, ADDRESS OF mask) = 0);
  64. ELSE
  65. thread[i] := self;
  66. END;
  67. END;
  68. END Initialize;
  69. (** Terminates the module and waits for all other processors to stop their execution. *)
  70. PROCEDURE Terminate-;
  71. VAR self: Unix.Thread_t; i: SIZE;
  72. BEGIN {UNCOOPERATIVE, UNCHECKED}
  73. self := Unix.pthread_self ();
  74. FOR i := 0 TO Maximum - 1 DO
  75. IF thread[i] # self THEN
  76. ASSERT (Unix.pthread_join (thread[i], NIL) = 0);
  77. END;
  78. END;
  79. ASSERT (Unix.sem_destroy (ADDRESS OF semaphore) = 0);
  80. END Terminate;
  81. END Processors.