ms_sync.c 4.06 KB
/**************************************************************************
 *									  *
 *		 Copyright (C) 1993, Silicon Graphics, Inc.		  *
 *									  *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *									  *
 **************************************************************************/

/*
 *  ms_sync.c $Revision: 1.3 $
 *
 *  master/slave syncronization routines
 */

#include "ms_sync.h"
#ifndef __sgi__
#include <sys/ipc.h>
#include <sys/sem.h>
union semun {
	int val;                    /* value for SETVAL */
	struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
	unsigned short int *array;  /* array for GETALL, SETALL */
	struct seminfo *__buf;      /* buffer for IPC_INFO */
};
#endif


/*
 *  Possible values for ms->slave[]
 */
#define MS_GARBAGE	-1
#define MS_SYNC_INIT	10
#define MS_CONTINUE	11
#define MS_DONE		12

/*
 *  Possible values for ms->active[]
 */
#define MS_INACTIVE	0
#define MS_ACTIVE	1

volatile ms_sync_t *ms;


void ms_init_master(long num_slaves)
{
    int i, j;

    /*
     *  Initialize ms structure.
     */
    ms->num_slaves = num_slaves;
    for (i = 0; i < num_slaves; i++)
    {
	ms->active[i] = MS_ACTIVE;
	ms->slave[i] = MS_GARBAGE;
    }
#ifndef __sgi__
    if ((ms->semaphore=semget(ms->key, 2, IPC_CREAT|0600)) < 0) {
        perror("semget");
	exit(1);
    }
    {
        union semun sv0, sv1;
	sv0.val = 0;
	sv1.val = 0;
	if (semctl(ms->semaphore, 0, SETVAL, sv0) < 0 ||
	    semctl(ms->semaphore, 1, SETVAL, sv1) < 0) {
	    perror("semctl");
	    exit(1);
	}
    }
#endif

    /*
     *  Syncronize with slaves
     */
    for (j = 0; j < 3; j++)
    {
        for (i = 0; i < ms->num_slaves;)
        {
	    if (ms->slave[i] == MS_DONE)
	        i++;
	    else
#ifdef __sgi__
	        sginap(0);
#else
	        usleep(0);
#endif
        }

        for (i = 0; i < ms->num_slaves; i++)
        {
	    ms->slave[i] = (j < 2) ? MS_SYNC_INIT : MS_CONTINUE;
        }
    }
}


void ms_init_slave(long id)
{
    /*
     *  signal master that this slave is done
     */
    ms->slave[id] = MS_DONE;

    /*
     *  Wait for the master to tell us to continue.
     */
    while (ms->slave[id] != MS_CONTINUE)
    {
	if (ms->slave[id] == MS_SYNC_INIT || ms->slave[id] == MS_GARBAGE)
	    ms->slave[id] = MS_DONE;
#ifdef __sgi__
	sginap(0);
#else
	usleep(0);
#endif
    }
#ifndef __sgi__
    if ((ms->semaphore=semget(ms->key, 2, IPC_CREAT|0600)) < 0) {
        perror("semget");
	exit(1);
    }
#endif
}


void ms_master_sync()
{
    int i;

#ifndef __sgi__
    struct sembuf sop;
    sop.sem_num = 0;
    sop.sem_op = -ms->num_slaves;
    sop.sem_flg = 0;
    if (semop(ms->semaphore, &sop, 1) < 0) {
    	perror("master1 semop");
	exit(1);
    }
#endif
    /*
     *  Wait for all active slaves to check in.
     */
    for (i = 0; i < ms->num_slaves;)
    {
	if (ms->slave[i] == MS_DONE || ms->active[i] == MS_INACTIVE)
	    i++;
    }

    /*
     *  Signal all slaves to continue.
     */
    for (i = 0; i < ms->num_slaves; i++)
    {
	ms->slave[i] = MS_CONTINUE;
    }
#ifndef __sgi__
    sop.sem_num = 1;
    sop.sem_op = ms->num_slaves;
    sop.sem_flg = 0;
    if (semop(ms->semaphore, &sop, 1) < 0) {
    	perror("master2 semop");
	exit(1);
    }
#endif
}


void ms_slave_sync(long id)
{
    /*
     *  signal master that this slave is done
     */
    ms->slave[id] = MS_DONE;
#ifndef __sgi__
{
    struct sembuf sop;
    sop.sem_num = 0;
    sop.sem_op = 1;
    sop.sem_flg = 0;
    if (semop(ms->semaphore, &sop, 1) < 0) {
    	perror("slave1 semop");
	exit(1);
    }
    sop.sem_num = 1;
    sop.sem_op = -1;
    sop.sem_flg = 0;
    if (semop(ms->semaphore, &sop, 1) < 0) {
    	perror("slave2 semop");
	exit(1);
    }
}
#endif

    /*
     *  Wait for the master to tell us to continue.
     */
    while (ms->slave[id] != MS_CONTINUE)
	;
}