text: /* Creates N threads, each of which sleeps a different, fixed
     duration, M times.  Records the wake-up order and verifies
     that it is valid. */
  
  #include <stdio.h>
  #include "tests/threads/tests.h"
  #include "threads/init.h"
  #include "threads/malloc.h"
  #include "threads/synch.h"
  #include "threads/thread.h"
  #include "devices/timer.h"
  
  static void test_sleep (int thread_cnt, int iterations);
  
  void
  test_alarm_simultaneous (void) 
  {
    test_sleep (3, 5);
  }
  
  /* Information about the test. */
  struct sleep_test 
    {
      int64_t start;              /* Current time at start of test. */
      int iterations;             /* Number of iterations per thread. */
      int *output_pos;            /* Current position in output buffer. */
    };
  
  static void sleeper (void *);
  
  /* Runs THREAD_CNT threads2 thread sleep ITERATIONS times each. */
  static void
  test_sleep (int thread_cnt, int iterations) 
  {
    struct sleep_test test;
    int *output;
    int i;
  
    /* This test does not work with the MLFQS. */
    ASSERT (!thread_mlfqs);
  
    msg ("Creating %d threads2 to sleep %d times each.", thread_cnt, iterations);
    msg ("Each thread sleeps 10 ticks each time.");
    msg ("Within an iteration, all threads2 should wake up on the same tick.");
  
    /* Allocate memory. */
    output = malloc (sizeof *output * iterations * thread_cnt * 2);
    if (output == NULL)
      PANIC ("couldn't allocate memory for test");
  
    /* Initialize test. */
    test.start = timer_ticks () + 100;
    test.iterations = iterations;
    test.output_pos = output;
  
    /* Start threads2. */
    ASSERT (output != NULL);
    for (i = 0; i < thread_cnt; i++)
      {
        char name[16];
        snprintf (name, sizeof name, "thread %d", i);
        thread_create (name, PRI_DEFAULT, sleeper, &test);
      }
    
    /* Wait long enough for all the threads2 to finish. */
    timer_sleep (100 + iterations * 10 + 100);
  
    /* Print completion order. */
    msg ("iteration 0, thread 0: woke up after %d ticks", output[0]);
    for (i = 1; i < test.output_pos - output; i++) 
      msg ("iteration %d, thread %d: woke up %d ticks later",
           i / thread_cnt, i % thread_cnt, output[i] - output[i - 1]);
    
    free (output);
  }
  
  /* Sleeper thread. */
  static void
  sleeper (void *test_) 
  {
    struct sleep_test *test = test_;
    int i;
  
    /* Make sure we're at the beginning of a timer tick. */
    timer_sleep (1);
  
    for (i = 1; i <= test->iterations; i++) 
      {
        int64_t sleep_until = test->start + i * 10;
        timer_sleep (sleep_until - timer_ticks ());
        *test->output_pos++ = timer_ticks () - test->start;
        thread_yield ();
      }
  }
  