/*
 *	KRoC scheduler startup code for occam
 *	Copyright (C) 1995, 1996, 1997 D.C.Wood, P.H.Welch
 *	Modified for OOS by Brian Vinter, 2002
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * $Source: /proj/ofa/rts/RCS/rtsmain.c,v $
 *
 * $Id: rtsmain.c,v 1.17 1997/09/03 15:42:33 djb1 Exp $
 *
 * (C) Copyright 1995,1996,1997 D.C. Wood <D.C.Wood@ukc.ac.uk> and 
 *                              P.H. Welch <P.H.Welch@ukc.ac.uk>
 * University of Kent at Canterbury
 *
 * Based on work by: Peter Shephard @ QMC Sept. 1984 for
 * UNIX OPS 2.0 (Release 2.0.1 : 24th. July, 1986)
 *
 * OOS hacks by Brian Vinter and Fred Barnes
 */

#define RTS_MAIN

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#if defined(OOS_BUILD)
	#include <oos_funcs.h>
#else	/* !OOS_BUILD */
	#include <unistd.h>
	#ifdef HAVE_STDLIB_H
	#include <stdlib.h>
	#endif
	#include <fcntl.h>
	#include <string.h>

	#ifdef ENABLE_CPU_TIMERS
		#include <pwd.h>
		#include <sys/types.h>
	#endif
#endif	/* !OOS_BUILD */

#include <rts.h>
#include <arch/sched_types.h>

/*{{{  externs*/
extern sync_type sf;

extern void keyboard_process (int user_pid, int to_user_fd, int from_user_fd, bool is_a_tty);
extern void user_process (int kbd_pid, int to_kbd_fd, int from_kbd_fd, bool is_a_tty);


/*}}}*/

#ifndef OOS_BUILD
/*{{{  RTS common variables*/

#ifndef BLOCKING_SYSCALLS
	/* Two pipes (socketpairs) */
	int kbd_chars[2];
	int kbd_ack[2];
#endif	/* !BLOCKING_SYSCALLS */

/*}}}*/
#endif	/* !OOS_BUILD */

/*{{{  RTS common variables*/
#ifdef DEBUG_RTS
bool trace;
#endif

#ifdef ENABLE_CPU_TIMERS
extern unsigned long glob_cpufactor;		/* in sched.c */
extern unsigned long glob_cpukhz;		/* in sched.c */
#endif

char *short_cmdline;
char *long_cmdline;

int kroc_argc;
char **kroc_argv;


#if !defined(OOS_BUILD)
static void savecmdline (int argc, char **argv);
extern int occam_uses_keyboard (void);
#endif

/*}}}*/

#if !defined(OOS_BUILD) && !defined(BLOCKING_SYSCALLS)
/*{{{  static int my_fork (void) {*/
static int my_fork (void)
{
	int n = 5;
	int cpid;

	do {
		if ((cpid = fork ()) != ERR) {
			return (cpid);
		} else {
			sleep (2);
		}
	} while (--n >= 0);

	fputs ("KRoC: fork() failed\n", stderr);
	exit (-1);
}  /* my_fork */
/*}}}*/
#endif	/* !OOS_BUILD && !BLOCKING_SYSCALLS */

#if !defined(OOS_BUILD)
/*{{{  static void savecmdline (int argc, char **argv)*/
static void savecmdline (int argc, char **argv)
{
	static char cmdline[512];
	int i = 0;

	cmdline[0] = '\0';
	long_cmdline = &cmdline[0];
	short_cmdline = &cmdline[0];
	while (i < argc) {
		strcat (cmdline, argv[i]);
		i++;
		if (i < argc) {
			strcat (cmdline, " ");  /* separate arguments except the last one */
		}
		if (i == 1) {
			short_cmdline = &cmdline[strlen(cmdline)];
		}
	}
	return;
}
/*}}}*/
#endif

#if defined(OOS_BUILD)
#include <arch/sched.h>
/*{{{  void occam_kernel_main (int argc, char **argv)*/
/*
 *	occam kernel run (for OOS)
 */
void occam_kernel_main (void)
{
	int is_a_tty, i;

	#ifdef DEBUG_RTS
		trace =  TRUE;
	#endif /* DEBUG_RTS */

  	is_a_tty = 1;

	#ifdef ENABLE_CPU_TIMERS
	{
		double cpumhz = oos_cpu_speed_mhz ();

		/* double cpumhz = 200.0; */
		glob_cpufactor = (unsigned long)((double)(1LL << 32) / cpumhz);
		glob_cpukhz = (unsigned long)(cpumhz * 1024.0);
	}
	#endif

	sf.u.combined_sync = 0;

	/* initialise interrupts */
	for (i=0; i<OOS_NUM_INTERRUPTS; i++) {
		inttab[i] = NULL;
		intcount[i] = 0;
		intlast = 0;
		iq_fptr = iq_bptr = NULL;
		ticount = 0;
	}
	oos_initialise_interrupts ();

	/* init_kbdio (is_a_tty); */
	user_process (-1, -1, -1, is_a_tty);

	/* keep compiler happy */
	return;
}  /* main */
/*}}}*/
#else	/* !OOS_BUILD */
/*{{{  int main (int argc, char **argv)*/
/*
 *	start here
 */
int main (int argc, char **argv)
{
	int is_a_tty;
	#ifndef BLOCKING_SYSCALLS
		int cpid;
	#endif

	kroc_argc = argc;
	kroc_argv = argv;
  
	savecmdline (argc, argv);

	#ifndef BLOCKING_SYSCALLS
		/*
		 * create pipes down which :-
		 *       (a) parent will send keyboard chars to occam;
		 *       (b) child will acknowledge with same char
		 *               (only when an Occam process inputs it);
		 */
		if (pipe (kbd_chars) == ERR || pipe (kbd_ack) == ERR) {
			fputs ("failed to create pipe (s)\n", stderr);
			exit (-3);
		}
	#endif	/* !BLOCKING_SYSCALLS */

	#ifdef DEBUG_RTS
		trace =  TRUE;
	#endif /* DEBUG_RTS */
  
	is_a_tty = isatty (0);

	if (is_a_tty && occam_uses_keyboard ()) {
		save_tty_state ();
	} else {
		is_a_tty = 0;
	}

	#ifdef ENABLE_CPU_TIMERS
	{
		FILE *fp;
		struct passwd *pwent;
		char tstr[FILENAME_MAX];
		double cpumhz;

		/* better read clock value from someplace */
		fp = fopen (".kroc_clock", "r");
		if (!fp) {
			/* try ~/.kroc_clock */
			pwent = getpwuid (getuid());
			if (pwent) {
				sprintf (tstr, "%s/.kroc_clock", pwent->pw_dir);
				fp = fopen (tstr, "r");
			}
		}
		if (!fp) {
			fp = fopen ("/etc/kroc_clock", "r");
		}
		if (fp) {
			if (fscanf (fp, "%lf", &cpumhz) != 1) {
				fprintf (stderr, "KRoC: error reading clock speed\n");
				restore_tty_state ();
				exit (1);
			}
		} else {
			fp = fopen("/proc/cpuinfo", "r");

			if (!fp) {
				fprintf (stderr, "KRoC: unable to find clock file (.kroc_clock, /etc/kroc_clock or /proc/cpuinfo)\n");
				restore_tty_state ();
				exit (1);
			}

			do {
				if (fgets (tstr, sizeof tstr, fp) == NULL) {
					fprintf (stderr, "KRoC: error reading clock speed\n");
					restore_tty_state ();
					exit (1);
				}
			} while (sscanf (tstr, "cpu MHz : %lf", &cpumhz) != 1);
		}
		fclose (fp);
		glob_cpufactor = (unsigned long)((double)(1LL << 32) / cpumhz);
		glob_cpukhz = (unsigned long)(cpumhz * 1024.0);
	}
	#endif

	sf.u.combined_sync = 0;

	#ifndef BLOCKING_SYSCALLS
		/* fork off process to run occam kernel */
		if ((cpid=my_fork ())) {
			/* parent */
			close (kbd_chars[1]);
			close (kbd_ack[0]);
    
			/* Close stdin = fd 0 = keyboard */
			/* fclose(stdin); */
    
			user_process (cpid, kbd_ack[1], kbd_chars[0], is_a_tty);
		} else {
			/* child */
			close (kbd_chars[0]);
			close (kbd_ack[1]);
    
			fclose(stdout);
    
			keyboard_process (getppid(), kbd_chars[1], kbd_ack[0], is_a_tty);
		}
	#else	/* BLOCKING_SYSCALLS */
		init_kbdio (is_a_tty);
		user_process (-1, -1, -1, is_a_tty);
	#endif	/* BLOCKING_SYSCALLS */
	/* keep compiler happy */
	return 0;
}  /* main */


/*}}}*/
#endif	/* !OOS_BUILD */


