private define slave_task (s,k)
{
   send_msg (s, SLAVE_READY);

   forever
     {
        variable r = recv_objs (s);
        variable index = r[0];

        if (index < 0)
          break;

        vmessage ("\n Slave %d is performing call %d\n", k, index);
        sleep (int(urand()*6));

        send_msg (s, SLAVE_RESULT);
        send_objs (s, k, index, index^2);
     }

   return 0;
}

private define maybe_finished (slaves)
{
   variable s;
   foreach s (slaves)
     {
        if (s.status != SLAVE_READY)
          return;
     }

   foreach s (slaves)
     {
        send_objs (s, -1);
     }
}

private variable Task_List;

private define send_next_task (s)
{
   if (Task_List.index < length(Task_List.value))
     {
        send_objs (s, Task_List.index);
        Task_List.index++;
        s.status = SLAVE_RUNNING;
     }
   else maybe_finished (s);
}

private define recv_slave_result (s)
{
   variable objs = recv_objs(s);
   Task_List.results[objs[1]] = objs[2];
   vmessage ("\n Thanks, slave %d, for doing call %d \n",objs[0],objs[1]);
   s.status = SLAVE_READY;
   return 0;
}

private define slave_handler(s,msg)
{
   switch (msg.type)
     {
      case SLAVE_READY:
        send_next_task (s);
     }
     {
      case SLAVE_RESULT:
        () = recv_slave_result(s);
        send_next_task(s);
     }
}

define slave_test ()
{
   variable num_tasks = 10;
   
   Task_List = struct {index, value, results};
   Task_List.index = 0;
   Task_List.value = [0:num_tasks-1];
   Task_List.results = Double_Type[length(Task_List.value)];

   variable num_slaves = min ([qualifier ("num_slaves", _num_cpus()),
                               num_tasks]);
   if (qualifier_exists ("serial"))
     num_slaves=1;

   variable k, s, slaves = new_slave_list ();
   _for k (0, num_slaves-1, 1)
     {
        s = fork_slave (&slave_task, k);
        append_slave (slaves, s);
     }

   manage_slaves (slaves, &slave_handler ;; __qualifiers);

   vmessage ("\n Here are the answers you seek:\n\n");
   print(Task_List.results);
   Task_List.index=0;   
}
