/*
 * Let a potentially large number of threads wait
 * for a mutex.
 *
 * Copyright © 2001  Keith Packard
 * All Rights Reserved.  See the file COPYING in this directory
 * for licensing information.
 */

autoimport Mutex;
bool die;

typedef struct {
    mutex	mut_ex;
    string	name;
} named_mutex;

int[*]		owned;
named_mutex[*]	mutexes;
mutex		owned_mutex = Mutex::new();
semaphore	started = Semaphore::new (0);

void status ()
{
    int nt = dim (owned);
    int i;

    
    twixt (acquire (owned_mutex); release (owned_mutex))
    {
	for (i = 0; i < nt; i++)
	{
	    if (owned[i] >= 0)
		printf ("%s", mutexes[owned[i]].name);
	    else
		printf (" ");
	}
	printf ("\n");
    }
}

void t (*(named_mutex[*]) mutexes, int self, int delay)
{
    int i;
    
    Semaphore::signal (started);
    die = false;
    while (!die)
    {
	for (i = 0; !die && i < dim (*mutexes); i++)
	{
	    twixt (acquire ((*mutexes)[i].mut_ex); 
		   release ((*mutexes)[i].mut_ex))
	    {
		twixt (acquire (owned_mutex); release (owned_mutex))
		    owned[self] = i;
		/* status(); */
		sleep (delay);
		twixt (acquire (owned_mutex); release (owned_mutex))
		    owned[self] = -1;
	    }
	   /*  printf ("Thread %v done with %v\n", Thread::current (),
		    (*mutexes)[i].mut_ex);*/
	}
    }
}

void start (int nthread, int nmut_ex, int delay)
{
    int i;

    owned = (int [nthread]) {};
    for (i = 0; i < nthread; i++)
	owned[i] = -1;
    mutexes = (named_mutex [nmut_ex]) {};
    for (i = 0; i < nmut_ex; i++)
    {
	mutexes[i] = (named_mutex) {
	    .mut_ex = new (),
	    .name = String::new('A' + i)
	};
    }
    for (i = 0; i < nthread; i++)
    {
	fork (t (&mutexes, i, delay));
	Semaphore::wait (started);
    }
}

void monitor (int delay)
{
    for (;;)
    {
	status ();
	sleep (delay);
    }
}

start (20, 10, 100);
monitor (200);
    
