./                                                                                                     755     146       0            0  5116557354   4143                                                                                                                                                                                                                                                                                                                                                                      ./FILES                                                                                                644     146       0          166  4555174350   4775                                                                                                                                                                                                                                                                                                                                                                      FILES
Makefile
assign.c
assign.h
cpu_request.defs
cpu_server.h
main.c
queue.h
request.c
request.h
task_special_user.c
                                                                                                                                                                                                                                                                                                                                                                                                          ./Makefile                                                                                             444     146       0         3235  4754611252   5664                                                                                                                                                                                                                                                                                                                                                                      #
# Mach Operating System
# Copyright (c) 1991,1990 Carnegie Mellon University
# All Rights Reserved.
# 
# Permission to use, copy, modify and distribute this software and its
# documentation is hereby granted, provided that both the copyright
# notice and this permission notice appear in all copies of the
# software, derivative works or modified versions, and any portions
# thereof, and that both notices appear in supporting documentation.
# 
# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
# CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
# 
# Carnegie Mellon requests users of this software to return to
# 
#  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
#  School of Computer Science
#  Carnegie Mellon University
#  Pittsburgh PA 15213-3890
# 
# any improvements or extensions that they make and grant Carnegie the
# rights to redistribute these changes.
#
#
# HISTORY
# $Log:	Makefile,v $
# Revision 2.3  91/02/08  16:05:46  mrt
# 	Added new Mach copyright and author notices
# 
# Revision 2.2  90/01/24  23:33:23  mrt
# 	Adapted from envmgr Makefile.
# 	[89/08/04            dlb]
# 
#
# 

#
# "make interface CPDIR=<where you're at>" to make the User (and Server)
# side of an RPC interface for the cpu_server.  This is called by lib/libmach
# to get the interface into the mach library.
#

INSTALL_DIR=$(DSTBASE)/etc
TARGET_DIRS=${INSTALL_DIR}
CPDIR= ""
COPY_H = cpu_server.h


SRCS = assign.c main.c request.c task_special_user.c
DEFS = cpu_request.defs
PRGM = cpu_server
LIBS = $(LIBTHREADS) $(LIBMACH)

include $(SRCBASE)/Make.inc

-include $(DEP_FILE)
                                                                                                                                                                                                                                                                                                                                                                   ./assign.c                                                                                             444     146       0        33654  4754611212   5700                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	assign.c,v $
 * Revision 2.3  91/02/08  16:05:15  mrt
 * 	For the multimax only, changed the maximum number of processors 
 * 	that may be assigned to N-1 rather than 3/4 of N.
 * 	[91/02/08            mrt]
 * 
 * Revision 2.2  90/01/24  23:33:26  mrt
 * 	Changed include of sys/message.h to mach/message.h and
 * 	sys/error.h to mach/error.h
 * 	[90/01/22            mrt]
 * 
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
 /*
 *	File:	assign.c
 *	Author:	David Black, Carnegie Mellon
 *	Date:	Jan 1990
 *
 *	Processor assignment control.
 */

#include <cthreads.h>
#include <mach/message.h>
#include <mach/error.h>

#include <stdio.h>

#include "request.h"

/*
 *	Initialize processors data structures.
 */

processor_init()
{
    int				size, i, j, k;
    int				temp;
    struct processor_basic_info	pinfo;
    struct host_basic_info	hinfo;
    processor_set_t		default_name;

    /*
     *	Get default processor set port.
     */
    processor_set_default(host_self(), &default_name);
    host_processor_set_priv(host_priv_self(), default_name, &default_set);

    /*
     *	Get processor ports, and set up max.
     */
    size = sizeof(hinfo)/sizeof(int);
    host_info(host_self(), HOST_BASIC_INFO, &hinfo, &size);
    host_processors(host_priv_self(), &processors, &processor_count);

    if (processor_count <= 1) {
	fprintf(stderr,
	    "Only %d processors; this server requires a multiprocessor!\n",
	    processor_count);
	exit(1);
    }
#if 	multimax
    max_processors = processor_count - 1;
#else	multimax
    max_processors = processor_count - (processor_count + 3)/4; 
#endif 	multimax
    free_processors = (run_processor_t)
			malloc(sizeof(run_processor_data_t)* max_processors);
    /*
     *	Loop through and pick out processors to control.  Can't use master.
     *  Assign all to default_set for sanity.
     */
    j = 0;			/* running count of processors allocated */
    for (i = 0; i < processor_count; i++) {
	size = PROCESSOR_BASIC_INFO_COUNT;
	processor_info(processors[i], PROCESSOR_BASIC_INFO, &temp,
		&pinfo, &size);
    	if (! pinfo.is_master) {
	    if (j < max_processors) {
		free_processors[j].this_processor = processors[i];
		if (j != 0)
		    free_processors[j-1].next = &(free_processors[j]);
		free_processors[j].next = RP_NULL;
		free_processors[j].status = FREE;
		free_processors[j].slot_num = pinfo.slot_num;
		processor_assign(free_processors[j].this_processor,
			default_set, TRUE);
		j++;
	    }
	    else {
		processor_assign(processors[i], default_set, TRUE);
	    }
	}
    }
    available_processors = j;

    /*
     *	Time policy.  No more than 15 minutes per slot.
     */
    max_time = 15*60;

    /*
     *	Total time policy.  No more than 2 hours total.
     */
    max_total_time = 2*60*60;

}


/*
 *	Release processors.  Assign all processors to default.
 */
release_processors(request)
request_t	request;

{
    run_processor_t this_proc, next_proc;

    if (request->options & CPU_OPTION_SUSPEND) {
	task_suspend_special(request->task);
	request->resume_needed = TRUE;
    }
    mutex_lock(&log_file_lock);
    print_time();
    printf("Releasing processors:");
    for (this_proc = request->processor_ids; this_proc != RP_NULL;
	this_proc = next_proc) {
	    next_proc = this_proc->next;
	    this_proc->status = FREE;
	    this_proc->next = free_processors;
	    free_processors = this_proc;
	    available_processors++;
	    processor_assign(this_proc->this_processor, default_set, FALSE);
	    printf(" %d", this_proc->slot_num);
    }
    printf("\n");
    fflush(stdout);
    mutex_unlock(&log_file_lock);
    request->assigned_processors = 0;
    request->processor_ids = RP_NULL;
}

/*
 *	assigned_request_insert - insert an assigned request into the
 *	time_queue.  Assigned requests are ordered by time of next event.
 */
assigned_request_insert(req)
request_t	req;
{
    register request_t	scan;

    if (queue_empty(&time_queue)) {
	queue_enter(&time_queue, req, request_t, active_req);
    }
    else {
	scan = queue_first(&time_queue);
	while ((!queue_end(&time_queue,scan)) &&
	       (scan->state == REQUEST_ASSIGNED)) {
		    if (scan->event_time >= req->event_time)
			break;
			
		    scan = scan->active_req.next;
	}
	if (queue_end(&time_queue, scan)) {
	    queue_enter(&time_queue, req, request_t, active_req);
	}
	else if (scan == queue_first(&time_queue)) {
	    queue_enter_first(&time_queue, req, request_t, active_req);
	}
	else {
	    register request_t	prev;

	    /*
	     *	Insert before scan, prev elt is a real element.
	     */
	    prev = scan->active_req.prev;
	    req->active_req.next = (queue_entry_t) scan;
	    prev->active_req.next = (queue_entry_t) req;
	    req->active_req.prev = (queue_entry_t) prev;
	    scan->active_req.prev = (queue_entry_t) req;
	}
    }
}

/*
 *	Assign processors to the first n requests on time_queue so as to 
 *	use up as many of the free processors as possible.
 *	Queue must be locked.
 */
assign_processors()
{
    int set_index, count, total_count;
    run_processor_t proc_ptr;
    request_t req, next_req;
    request_t scan;
    int delay_time;
    boolean_t wait;

    /*
     *	Skip already assigned requests.
     */
    req = queue_first(&time_queue);
    while ((!queue_end(&time_queue, req)) &&
	   (req->state == REQUEST_ASSIGNED))
		req = req->active_req.next;

    /*
     *	Loop to assign as many requests in order as possible.
     */
    while ((!queue_end(&time_queue, req)) &&
      (available_processors >= req->total_processors)) {

	/*
	 *	Initialize assign loop.
	 */
	request_lock(req);
	next_req = req->active_req.next;
	queue_remove(&time_queue, req, request_t, active_req);
    	set_index = 0;
    	total_count = 0;
	count = req->processors[0];
	mutex_lock(&log_file_lock);
	print_time();
	printf("Assigning processors to %d:", req);
	wait = ((req->options & CPU_OPTION_NOTIFY) != 0);

	/*
	 * Assign processors to this request.
	 */
	while (total_count < req->total_processors) {
	    /*
	     *	Errors here are caused by clients.  Ignore them.
	     */
	    proc_ptr = free_processors;
	    free_processors = proc_ptr->next;
	    proc_ptr->status = BUSY;
	    printf(" %d",proc_ptr->slot_num);
	    processor_assign(proc_ptr->this_processor, req->sets[set_index],
			wait);
	    proc_ptr->next = req->processor_ids;
	    req->processor_ids = proc_ptr;
	    total_count++;
	    count--;
	    if (count == 0) {
	        set_index++;
	    	count = req->processors[set_index];
	    }
	}
	printf("\n");
	fflush(stdout);
	mutex_unlock(&log_file_lock);

	/*
	 *	Now place this request at the proper place in the time queue.
	 */
	req->event_time = current_time() + req->run_time;
	available_processors -= req->total_processors;
	req->state = REQUEST_ASSIGNED;
	req->assigned_processors = req->total_processors;
	assigned_request_insert(req);

	/*
	 *	Handle start options.
	 */
	if (req->options & CPU_OPTION_NOTIFY) {
	    send_notify(req, CPU_NOTIFY_START);
	}
	if ((req->options & CPU_OPTION_SUSPEND) && req->resume_needed) {
	    task_resume_special(req->task);
	    req->resume_needed = FALSE;
	}
	    
	request_unlock(req);
	req = next_req;
    }
}

/*
 *	destroy_sets() - destroy psets in request.
 */
destroy_sets(request)
request_t	request;
{
    int		i;

    for (i = 0; i < request->set_count; i++) {
	/*
	 *	Errors here are caused by users.  Ignore them.
	 */
	processor_set_destroy(request->sets[i]);
    }
}

/*
 *	Compute time until next event.  Make sure it's never negative.
 */

compute_wait_duration()
{
    int delay_time, duration;
    request_t req;

    duration = max_time+1;
    req = queue_first(&time_queue);
    while ((! queue_end(&time_queue, req)) &&
    		(req->state == REQUEST_ASSIGNED)) {
	delay_time = req->event_time - current_time();
	if (delay_time < duration) duration = delay_time;
	req = req->active_req.next;
    }
    if (duration < 0)
    	duration = 0;

    return(duration);
}

/*
 *	Body of the thread that runs around assigning processors.
 */

port_t	private_port;

void
run_time_queue()
{
    request_t cur_req, next_req;
    int duration;
    int time_now;
    
    time_thread = thread_self();
    port_allocate(task_self(), &private_port);

    mutex_lock(&time_queue_lock);

    while(1) {
	/*
	 *	Processors not assigned.  Wait on condition until
	 *	request at front of queue can be handled.
	 */
	while (queue_empty(&time_queue)) {
		condition_wait(&time_queue_condition, &time_queue_lock);
	}

	/*
	 *	Ok, assign processors.
	 */
	assign_processors();
	duration = compute_wait_duration();
	mutex_unlock(&time_queue_lock);

	/*
	 *	Now wait for time to expire or the current request to
	 *	be destroyed.
	 */
	if (duration > 0)
		wait_for(duration);

	/*
	 *	Process any events that have occurred.
	 */
	mutex_lock(&time_queue_lock);
	cur_req = queue_first(&time_queue);
	
	while ((! queue_end(&time_queue, cur_req)) &&
	  (cur_req->state == REQUEST_ASSIGNED)) {
	    /*
	     *	Check if out of events.
	     */
	    time_now = current_time();
	    if (cur_req->event_time > time_now) {
		break;
	    }

	    next_req = cur_req->active_req.next;
	    if (cur_req->options & CPU_OPTION_NOTIFY &&
	    	!(cur_req->end_notify_done)) {
		    /*
		     *	Request wants an end notify.  Send it and
		     *  give the request another second.
		     */
		    request_lock(cur_req);
		    queue_remove(&time_queue, cur_req,
			request_t, active_req);
		    cur_req->event_time = time_now + 10;
		    send_notify(cur_req, CPU_NOTIFY_END);
		    cur_req->end_notify_done = TRUE;		
		    assigned_request_insert(cur_req);
		    request_unlock(cur_req);
	    }
	    else {    
		    /*
		     * Request is finished.  Release its processors, and
		     * figure out what to do with it.
		     */
		    request_lock(cur_req);
		    queue_remove(&time_queue, cur_req,
			request_t, active_req);
		    cur_req->total_time -= cur_req->run_time;
		    release_processors(cur_req);

		    if ((cur_req->options & CPU_OPTION_REPEAT) &&
		    	(cur_req->total_time > 0)) {
			    /*
			     *	This is a repeating request with time to
			     *	go.  Restart it to continue.
			     */
			    cur_req->state = REQUEST_ACTIVATED;
			    if (cur_req->run_time > cur_req->total_time)
				cur_req->run_time = cur_req->total_time;
			    queue_enter(&time_queue, cur_req, request_t,
				active_req);
			    cur_req->end_notify_done = FALSE;
			    request_unlock(cur_req);

			    mutex_lock(&log_file_lock);
			    print_time();
			    printf("Reactivated %d: %d processors\n",
				cur_req, cur_req->total_processors);
			    fflush(stdout);
			    mutex_unlock(&log_file_lock);
		    }
		    else {
			    /*
			     * This request is finished.
			     */
			    cur_req->state = REQUEST_DEAD;
			    if (cur_req->options & CPU_OPTION_SUSPEND)
			    	task_resume_special(cur_req->task);
			    request_unlock(cur_req);
			    request_deallocate(cur_req);
		    }
	    }
	    cur_req = next_req;
	}
    }
}
	
/*
 *	wait_for - wait for time specified or until aborted.
 */
 
wait_for(time)
int	time;
{
    struct wait_for_message {
	msg_header_t	header;
    } wait_msg;
    mach_error_t	code;

    wait_msg.header.msg_local_port = private_port;
    wait_msg.header.msg_size = sizeof(wait_msg); 
    code = msg_receive(&wait_msg, RCV_TIMEOUT, time*100);
    if (code == RCV_SUCCESS || code == RCV_TIMED_OUT) {
	return;
    }

    mach_error("wait_for", code);
    exit(1);
}

/*
 *	abort_wait - abort timeout by sending message to private port.
 */

abort_wait()
{
    kern_return_t	ret;
    struct {
	msg_header_t	header;
    } abort_msg;

    abort_msg.header.msg_simple = TRUE;
    abort_msg.header.msg_size = sizeof(abort_msg);
    abort_msg.header.msg_type = MSG_TYPE_NORMAL;
    abort_msg.header.msg_remote_port = private_port;
    abort_msg.header.msg_local_port = PORT_NULL;

    ret = msg_send(&abort_msg, MSG_OPTION_NONE, 0);

    if (ret == SEND_SUCCESS) {
    	return;
    }

    mach_error("abort_wait", ret);
    exit(1);
}

/*
 *	send_notify - notify client of event.  Notification is sent with
 *		a timeout of zero.  It is the client's responsibility
 *		to prevent the notify_port from filling up.
 */
send_notify(request, type)
request_t	request;
int		type;
{
    struct {
	msg_header_t	header;
	msg_type_t	request_type;
	port_t		request_port;
    } notify_msg;

    static msg_type_t request_portType = {
		/* msg_type_name = */		MSG_TYPE_PORT,
		/* msg_type_size = */		32,
		/* msg_type_number = */		1,
		/* msg_type_inline = */		TRUE,
		/* msg_type_longform = */	FALSE,
		/* msg_type_deallocate = */	FALSE,
    };
    
    notify_msg.header.msg_simple = TRUE;
    notify_msg.header.msg_size = sizeof(notify_msg);
    notify_msg.header.msg_type = MSG_TYPE_NORMAL;
    notify_msg.header.msg_remote_port = request->notify_port;
    notify_msg.header.msg_local_port = PORT_NULL;
    notify_msg.header.msg_id = type;
    notify_msg.request_type = request_portType;
    notify_msg.request_port = request->port;

    /*
     *	All errors here are caused by clients.  Ignore them.
     */
    mutex_lock(&log_file_lock);
    print_time();
    printf("Sending notification %d for %d\n", type, request);
    fflush(stdout);
    mutex_unlock(&log_file_lock);
    msg_send(&notify_msg, SEND_TIMEOUT, 0);
}
_ptr;
    request_t req, next_req;
    request_t scan;
    int delay_time;
    boole./assign.h                                                                                             444     146       0         3623  4756562734   5676                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	assign.h,v $
 * Revision 2.3  91/02/14  14:32:45  mrt
 * 	Changed to new Mach copyright
 * 
 * Revision 2.2  90/01/24  23:33:30  mrt
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	assign.h
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	assign.h - Header file for processor assignment management.
 */

processor_set_t		default_set;

processor_t		*processors;
int			processor_count;

struct run_processor {
    	struct run_processor	*next;
	processor_t		this_processor;
	int			slot_num;
	int			status;		/* FREE or BUSY */
};

typedef	struct run_processor	run_processor_data_t;
typedef struct run_processor	*run_processor_t;

#define	FREE	0
#define	BUSY	1

#define RP_NULL	(run_processor_t)0

#define	MIN_PROCESSORS			0
#define MIN_TIME			0

run_processor_t		free_processors;

int	max_time;
int	max_total_time;
int	max_processors;
int	available_processors;

RMAL;
    notify_msg.header.msg_remote_port = request->notify_port;
    notify_msg.header.msg_local_port = PO./assign_test.c                                                                                        444     146       0        33614  4754611221   6733                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	assign_test.c,v $
 * Revision 2.3  91/02/08  16:05:22  mrt
 * 	Added new Mach copyright and author notices
 * 
 * Revision 2.2  90/01/24  23:33:33  mrt
 * 	Changed include of sys/message.h to mach/message.h and
 * 	sys/error.h to mach/error.h
 * 	[90/01/22            mrt]
 * 
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	assign_test.c
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	assign.c - Processor assignment control.
 */

#include <mach.h>
#include <cthreads.h>
#include <mach/message.h>
#include <mach/error.h>

#include <stdio.h>

#include "request.h"

unsigned long *ctr_address, *mapfrcounter();

/*
 *	Initialize processors data structures.
 */

processor_init()
{
    int				size, i, j, k;
    int				temp;
    struct processor_basic_info	pinfo;
    struct host_basic_info	hinfo;
    processor_set_t		default_name;

    /*
     *	Get default processor set port.
     */
    processor_set_default(host_self(), &default_name);
    host_processor_set_priv(host_priv_self(), default_name, &default_set);

    /*
     *	Get processor ports, and set up max.
     */
    size = sizeof(hinfo)/sizeof(int);
    host_info(host_self(), HOST_BASIC_INFO, &hinfo, &size);
    host_processors(host_priv_self(), &processors, &processor_count);

    if (processor_count <= 1) {
	fprintf(stderr,
	    "Only %d processors; this server requires a multiprocessor!\n",
	    processor_count);
	exit(1);
    }
    max_processors = processor_count - (processor_count + 3)/4; 
    free_processors = (run_processor_t)
			malloc(sizeof(run_processor_data_t)* max_processors);
    /*
     *	Loop through and pick out processors to control.  Can't use master.
     *  Assign all to default_set for sanity.
     */
    j = 0;			/* running count of processors allocated */
    for (i = 0; i < processor_count; i++) {
	size = PROCESSOR_BASIC_INFO_COUNT;
	processor_info(processors[i], PROCESSOR_BASIC_INFO, &temp,
		&pinfo, &size);
    	if (! pinfo.is_master) {
	    if (j < max_processors) {
		free_processors[j].this_processor = processors[i];
		if (j != 0)
		    free_processors[j-1].next = &(free_processors[j]);
		free_processors[j].next = RP_NULL;
		free_processors[j].status = FREE;
		free_processors[j].slot_num = pinfo.slot_num;
		processor_assign(free_processors[j].this_processor,
			default_set, TRUE);
		j++;
	    }
	    else {
		processor_assign(processors[i], default_set, TRUE);
	    }
	}
    }
    available_processors = j;

    /*
     *	Time policy.  No more than 15 minutes per slot.
     */
    max_time = 15*60;

    /*
     *	Total time policy.  No more than 2 hours total.
     */
    max_total_time = 2*60*60;

    /*
     *	Map counter and touch it to fault it in.
     */
    ctr_address = mapfrcounter(0, TRUE);
    i = *ctr_address;
}


/*
 *	Release processors.  Assign all processors to default.
 */
release_processors(request)
request_t	request;

{
    run_processor_t this_proc, next_proc;
    unsigned long	before, after;

    before = *ctr_address;
    if (request->options & CPU_OPTION_SUSPEND) {
	task_suspend_special(request->task);
	request->resume_needed = TRUE;
    }
    for (this_proc = request->processor_ids; this_proc != RP_NULL;
	this_proc = next_proc) {
	    next_proc = this_proc->next;
	    this_proc->status = FREE;
	    this_proc->next = free_processors;
	    free_processors = this_proc;
	    available_processors++;
	    processor_assign(this_proc->this_processor, default_set, FALSE);
    }
    request->assigned_processors = 0;
    request->processor_ids = RP_NULL;
    after = *ctr_address;
    printf("Release elapsed: %d\n", after - before);
}

/*
 *	assigned_request_insert - insert an assigned request into the
 *	time_queue.  Assigned requests are ordered by time of next event.
 */
assigned_request_insert(req)
request_t	req;
{
    register request_t	scan;

    if (queue_empty(&time_queue)) {
	queue_enter(&time_queue, req, request_t, active_req);
    }
    else {
	scan = queue_first(&time_queue);
	while ((!queue_end(&time_queue,scan)) &&
	       (scan->state == REQUEST_ASSIGNED)) {
		    if (scan->event_time >= req->event_time)
			break;
			
		    scan = scan->active_req.next;
	}
	if (queue_end(&time_queue, scan)) {
	    queue_enter(&time_queue, req, request_t, active_req);
	}
	else if (scan == queue_first(&time_queue)) {
	    queue_enter_first(&time_queue, req, request_t, active_req);
	}
	else {
	    register request_t	prev;

	    /*
	     *	Insert before scan, prev elt is a real element.
	     */
	    prev = scan->active_req.prev;
	    req->active_req.next = (queue_entry_t) scan;
	    prev->active_req.next = (queue_entry_t) req;
	    req->active_req.prev = (queue_entry_t) prev;
	    scan->active_req.prev = (queue_entry_t) req;
	}
    }
}

/*
 *	Assign processors to the first n requests on time_queue so as to 
 *	use up as many of the free processors as possible.
 *	Queue must be locked.
 */
assign_processors()
{
    int set_index, count, total_count;
    run_processor_t proc_ptr;
    request_t req, next_req;
    request_t scan;
    int delay_time;
    boolean_t wait;

    /*
     *	Skip already assigned requests.
     */
    req = queue_first(&time_queue);
    while ((!queue_end(&time_queue, req)) &&
	   (req->state == REQUEST_ASSIGNED))
		req = req->active_req.next;

    /*
     *	Loop to assign as many requests in order as possible.
     */
    while ((!queue_end(&time_queue, req)) &&
      (available_processors >= req->total_processors)) {

	/*
	 *	Initialize assign loop.
	 */
	request_lock(req);
	next_req = req->active_req.next;
	queue_remove(&time_queue, req, request_t, active_req);
    	set_index = 0;
    	total_count = 0;
	count = req->processors[0];
	mutex_lock(&log_file_lock);
	print_time();
	printf("Assigning processors to %d:", req);
	wait = ((req->options & CPU_OPTION_NOTIFY) != 0);

	/*
	 * Assign processors to this request.
	 */
	while (total_count < req->total_processors) {
	    /*
	     *	Errors here are caused by clients.  Ignore them.
	     */
	    proc_ptr = free_processors;
	    free_processors = proc_ptr->next;
	    proc_ptr->status = BUSY;
	    printf(" %d",proc_ptr->slot_num);
	    processor_assign(proc_ptr->this_processor, req->sets[set_index],
			wait);
	    proc_ptr->next = req->processor_ids;
	    req->processor_ids = proc_ptr;
	    total_count++;
	    count--;
	    if (count == 0) {
	        set_index++;
	    	count = req->processors[set_index];
	    }
	}
	printf("\n");
	fflush(stdout);
	mutex_unlock(&log_file_lock);

	/*
	 *	Now place this request at the proper place in the time queue.
	 */
	req->event_time = current_time() + req->run_time;
	available_processors -= req->total_processors;
	req->state = REQUEST_ASSIGNED;
	req->assigned_processors = req->total_processors;
	assigned_request_insert(req);

	/*
	 *	Handle start options.
	 */
	if (req->options & CPU_OPTION_NOTIFY) {
	    send_notify(req, CPU_NOTIFY_START);
	}
	if ((req->options & CPU_OPTION_SUSPEND) && req->resume_needed) {
	    task_resume_special(req->task);
	    req->resume_needed = FALSE;
	}
	    
	request_unlock(req);
	req = next_req;
    }
}

/*
 *	destroy_sets() - destroy psets in request.
 */
destroy_sets(request)
request_t	request;
{
    int		i;

    for (i = 0; i < request->set_count; i++) {
	/*
	 *	Errors here are caused by users.  Ignore them.
	 */
	processor_set_destroy(request->sets[i]);
    }
}

/*
 *	Compute time until next event.  Make sure it's never negative.
 */

compute_wait_duration()
{
    int delay_time, duration;
    request_t req;

    duration = max_time+1;
    req = queue_first(&time_queue);
    while ((! queue_end(&time_queue, req)) &&
    		(req->state == REQUEST_ASSIGNED)) {
	delay_time = req->event_time - current_time();
	if (delay_time < duration) duration = delay_time;
	req = req->active_req.next;
    }
    if (duration < 0)
    	duration = 0;

    return(duration);
}

/*
 *	Body of the thread that runs around assigning processors.
 */

port_t	private_port;

void
run_time_queue()
{
    request_t cur_req, next_req;
    int duration;
    int time_now;
    
    time_thread = thread_self();
    port_allocate(task_self(), &private_port);

    mutex_lock(&time_queue_lock);

    while(1) {
	/*
	 *	Processors not assigned.  Wait on condition until
	 *	request at front of queue can be handled.
	 */
	while (queue_empty(&time_queue)) {
		condition_wait(&time_queue_condition, &time_queue_lock);
	}

	/*
	 *	Ok, assign processors.
	 */
	assign_processors();
	duration = compute_wait_duration();
	mutex_unlock(&time_queue_lock);

	/*
	 *	Now wait for time to expire or the current request to
	 *	be destroyed.
	 */
	if (duration > 0)
		wait_for(duration);

	/*
	 *	Process any events that have occurred.
	 */
	mutex_lock(&time_queue_lock);
	cur_req = queue_first(&time_queue);
	
	while ((! queue_end(&time_queue, cur_req)) &&
	  (cur_req->state == REQUEST_ASSIGNED)) {
	    /*
	     *	Check if out of events.
	     */
	    time_now = current_time();
	    if (cur_req->event_time > time_now) {
		break;
	    }

	    next_req = cur_req->active_req.next;
	    if (cur_req->options & CPU_OPTION_NOTIFY &&
	    	!(cur_req->end_notify_done)) {
		    /*
		     *	Request wants an end notify.  Send it and
		     *  give the request another second.
		     */
		    request_lock(cur_req);
		    queue_remove(&time_queue, cur_req,
			request_t, active_req);
		    cur_req->event_time = time_now + 10;
		    send_notify(cur_req, CPU_NOTIFY_END);
		    cur_req->end_notify_done = TRUE;		
		    assigned_request_insert(cur_req);
		    request_unlock(cur_req);
	    }
	    else {    
		    /*
		     * Request is finished.  Release its processors, and
		     * figure out what to do with it.
		     */
		    request_lock(cur_req);
		    queue_remove(&time_queue, cur_req,
			request_t, active_req);
		    cur_req->total_time -= cur_req->run_time;
		    release_processors(cur_req);

		    if ((cur_req->options & CPU_OPTION_REPEAT) &&
		    	(cur_req->total_time > 0)) {
			    /*
			     *	This is a repeating request with time to
			     *	go.  Restart it to continue.
			     */
			    cur_req->state = REQUEST_ACTIVATED;
			    if (cur_req->run_time > cur_req->total_time)
				cur_req->run_time = cur_req->total_time;
			    queue_enter(&time_queue, cur_req, request_t,
				active_req);
			    cur_req->end_notify_done = FALSE;
			    request_unlock(cur_req);

			    mutex_lock(&log_file_lock);
			    print_time();
			    printf("Reactivated %d: %d processors\n",
				cur_req, cur_req->total_processors);
			    fflush(stdout);
			    mutex_unlock(&log_file_lock);
		    }
		    else {
			    /*
			     * This request is finished.
			     */
			    cur_req->state = REQUEST_DEAD;
			    if (cur_req->options & CPU_OPTION_SUSPEND)
			    	task_resume_special(cur_req->task);
			    request_unlock(cur_req);
			    request_deallocate(cur_req);
		    }
	    }
	    cur_req = next_req;
	}
    }
}
	
/*
 *	wait_for - wait for time specified or until aborted.
 */
 
wait_for(time)
int	time;
{
    struct wait_for_message {
	msg_header_t	header;
    } wait_msg;
    mach_error_t	code;

    wait_msg.header.msg_local_port = private_port;
    wait_msg.header.msg_size = sizeof(wait_msg); 
    code = msg_receive(&wait_msg, RCV_TIMEOUT, time*100);
    if (code == RCV_SUCCESS || code == RCV_TIMED_OUT) {
	return;
    }

    mach_error("wait_for", code);
    exit(1);
}

/*
 *	abort_wait - abort timeout by sending message to private port.
 */

abort_wait()
{
    kern_return_t	ret;
    struct {
	msg_header_t	header;
    } abort_msg;

    abort_msg.header.msg_simple = TRUE;
    abort_msg.header.msg_size = sizeof(abort_msg);
    abort_msg.header.msg_type = MSG_TYPE_NORMAL;
    abort_msg.header.msg_remote_port = private_port;
    abort_msg.header.msg_local_port = PORT_NULL;

    ret = msg_send(&abort_msg, MSG_OPTION_NONE, 0);

    if (ret == SEND_SUCCESS) {
    	return;
    }

    mach_error("abort_wait", ret);
    exit(1);
}

/*
 *	send_notify - notify client of event.  Notification is sent with
 *		a timeout of zero.  It is the client's responsibility
 *		to prevent the notify_port from filling up.
 */
send_notify(request, type)
request_t	request;
int		type;
{
    struct {
	msg_header_t	header;
	msg_type_t	request_type;
	port_t		request_port;
    } notify_msg;

    static msg_type_t request_portType = {
		/* msg_type_name = */		MSG_TYPE_PORT,
		/* msg_type_size = */		32,
		/* msg_type_number = */		1,
		/* msg_type_inline = */		TRUE,
		/* msg_type_longform = */	FALSE,
		/* msg_type_deallocate = */	FALSE,
    };
    
    notify_msg.header.msg_simple = TRUE;
    notify_msg.header.msg_size = sizeof(notify_msg);
    notify_msg.header.msg_type = MSG_TYPE_NORMAL;
    notify_msg.header.msg_remote_port = request->notify_port;
    notify_msg.header.msg_local_port = PORT_NULL;
    notify_msg.header.msg_id = type;
    notify_msg.request_type = request_portType;
    notify_msg.request_port = request->port;

    /*
     *	All errors here are caused by clients.  Ignore them.
     */
    mutex_lock(&log_file_lock);
    print_time();
    printf("Sending notification %d for %d\n", type, request);
    fflush(stdout);
    mutex_unlock(&log_file_lock);
    msg_send(&notify_msg, SEND_TIMEOUT, 0);
}
_ptr;
    request_t req, next_req;
    request_t scan;
    int delay_time;
    boolean_t wait;

    /*
     *	Skip a./cpu_request.defs                                                                                     444     146       0         6624  4754611205   7431                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	cpu_request.defs,v $
 * Revision 2.3  91/02/08  16:05:10  mrt
 * 	Added new Mach copyright and author notices
 * 
 * Revision 2.2  90/01/24  23:33:36  mrt
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	cpu_request.defs
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	MiG definition file for processor_server
 */

subsystem cpu_request 3000;

#include <mach/mach_types.defs>
type cpu_request_t		= port_t;

import <servers/cpu_server.h>;

/*
 *	Reserve processors for the processor sets according to the
 *	requests.  Would like to do this in one call, but MiG can't
 *	handle arrays of structures that contain ports or more than
 *	one inline array per message.
 */

routine cpu_request_create(
		server			: port_t;
		total_processors	: int;
		time			: int;
	out	delay			: int;
	out	cpu_request		: cpu_request_t);

routine cpu_request_add(
		cpu_request		: cpu_request_t;
		processor_set		: processor_set_t;
		processors		: int;
	out	processors_left		: int);
		

/*
 *	Activate processors for reservation.  The maximum delay until
 *	the reservation is satisfied is returned.  options is used to
 *	request options in handling the request (e.g. destroy when done).
 */

routine cpu_request_activate(
		cpu_request		: cpu_request_t;
		options			: int;
		total_time		: int;
	out	delay			: int);

/*
 *	Destroy request, releasing any processors.  Only destroys processor
 *	sets if destroy_when_done was requested.
 */

routine cpu_request_destroy(
		cpu_request		: cpu_request_t);

/*
 *	Find out information about a request.
 */

routine cpu_request_status(
		cpu_request		: cpu_request_t;
	out	reserved_processors	: int;
	out	assigned_processors	: int;
	out	active			: boolean_t;
	out	options			: int;
	out	time			: int);

/*
 *	Find out information about the server.
 */

routine cpu_server_info(
		server			: port_t;
	out	max_time		: int;
	out	max_total_time		: int;
	out	max_processors		: int;
	out	delay			: int);

/*
 *	Indicate that request should generate notifications and
 *	where they should be sent.
 */

routine cpu_request_set_notify(
		cpu_request		: cpu_request_t;
		notify_port		: port_t);

/*
 *	Variant of cpu_request_activate for a single task.  Allows server
 *	to optimize release of processors if task is still running.
 */

routine cpu_request_activate_task(
		cpu_request		: cpu_request_t;
		options			: int;
		total_time		: int;
		task			: task_t;
	out	delay			: int);
  request_t req, next_req;
    request_t scan;
    int delay_time;
    boolean_t wait;

    /*
     *	Skip a./cpu_server.h                                                                                         444     146       0         4127  4756562741   6565                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	cpu_server.h,v $
 * Revision 2.3  91/02/14  14:32:50  mrt
 * 	Changed to new Mach copyright
 * 
 * Revision 2.2  90/01/24  23:33:39  mrt
 * 	Changed include of sys/error.h to mach/error.h
 * 	[90/01/22            mrt]
 * 
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	cpu_server.h
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 */

#ifndef	_SERVERS_CPU_SERVER_
#define	_SERVERS_CPU_SERVER_

#include <servers/cpu_request.h>
/*
 *	Definitions needed by users of the cpu_server.
 */

typedef port_t		cpu_request_t;

/*
 *	Options for cpu_request activate.
 */

#define CPU_OPTION_NONE			0
#define CPU_OPTION_DESTROY		0x1
#define CPU_OPTION_REPEAT		0x2

#define CPU_VALID_OPTIONS		0x3


/*
 *	Notification types
 */

#define CPU_NOTIFY_START	1
#define CPU_NOTIFY_END		2

/*
 *	Errors for cpu server.
 */

#include <mach/error.h>

#define CPU_SUCCESS		(ERR_SUCCESS)
#define CPU_INVALID_ARGUMENT	(err_server|err_sub(4)|1)
#define CPU_LIMIT_EXCEEDED	(err_server|err_sub(4)|2)
#define CPU_REQUEST_ACTIVE	(err_server|err_sub(4)|3)

#endif	_SERVERS_CPU_SERVER_
satisfied is returned.  options is used to
 *	request options in handling the request (e.g. destroy when done).
 */

routine cpu_request_activate(
		cpu_request		: cpu_request_t;
		options			: int;
		total_time		: int;
	out	delay			: int);

/*
 *	Destroy request, releasing any processors.  Only destroys processor
 *	sets if destroy_when_done was requested.
 */

routine cpu_request_destroy(
		cpu_request		: cpu_request_t);./main.c                                                                                               444     146       0        10536  4754611177   5344                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	main.c,v $
 * Revision 2.3  91/02/08  16:05:04  mrt
 * 	Added a task_set_notify_port to PORT_NULL in the
 * 	initialization, to avoid notify messages building up.
 * 	[91/02/08            mrt]
 * 
 * Revision 2.2  90/01/24  23:33:41  mrt
 * 	Changed include of sys/message.h to mach/message.h and 
 * 	sys/error.h to mach/error.h
 * 	[90/01/22            mrt]
 * 
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	main.c
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	Main file for cpu server
 */

#include <mach.h>
#include <mach/message.h>
#include <mach/error.h>
#include <sys/time.h>

#include <servers/netname.h>

#include <stdio.h>

#include "request.h"

main(argc, argv)
int	argc;
char	*argv[];
{
    mach_error_t	code;
    int			count;
    port_t		port;
    extern int	run_time_queue();

    /*
     *	Initialize everything.
     */
    port_allocate(task_self(), &server_port);
    port_set_allocate(task_self(), &server_port_set);
    port_set_add(task_self(), server_port_set, server_port);
    task_set_notify_port(task_self(),PORT_NULL);

    request_init();
    processor_init();
    mutex_init(&log_file_lock);

    /*
     *	Fork off second cthread.  It should immediately wait on time_queue.
     */
    time_thread = (thread_t)0;
    cthread_detach(cthread_fork(run_time_queue, 0));
    while (time_thread == (thread_t)0)
    		;
    printf("main: started time_thread.\n");
    fflush(stdout);

    /*
     *  Register our name with name-service, then loop processing requests.
     *  Make sure the name service is there first; be patient.
     */
    count = 0;
    while (1) {
	if (netname_look_up(name_server_port,"","NM_ACTIVE",&port)
	    == KERN_SUCCESS) {
		break;
	}
	if (++count > 1000) {
	    printf ("Could not contact name_server\n");
	    exit(1);
	}
	sleep(3);
    }
	
	
    code = netname_check_in(name_server_port, "cpu_server", PORT_NULL,
		server_port);
    if (code != ERR_SUCCESS) {
	mach_error("netname_check_in", code);
	exit(1);
    }
    print_time();
    printf("main: checked in port as 'cpu_server'\n");
    fflush(stdout);

    server_loop();
}


/*
 *	server_loop() - read and process messages.
 */

struct	cpu_msg {
    msg_header_t	head;
    int			space[200];
} in_msg, out_msg;

server_loop()
{
    mach_error_t	retcode;
    boolean_t		ok, cpu_request_server();

    while (1) {
	in_msg.head.msg_size = sizeof(in_msg);
	in_msg.head.msg_local_port = server_port_set;

	retcode = msg_receive(&in_msg, MSG_OPTION_NONE, 0);
	if (retcode == RCV_SUCCESS) {
	    ok = cpu_request_server(&in_msg, &out_msg);
	    
	    /*
	     *	All actions have replies.
	     */
	    if (ok) {
		retcode = msg_send(&out_msg, MSG_OPTION_NONE, 0);
    
		if (retcode != SEND_SUCCESS) {
		    printf("server_loop: error %s at msg_send.\n",
			mach_error_string(retcode));
		}
	    }
	    else {
		printf("server_loop: server didn't recognize message.\n");
		fflush(stdout);
	    }
	}
	else {
		printf("server_loop: error %s at msg_receive.\n",
			mach_error_string(retcode));
		fflush(stdout);
	}
    }
}


/*
 *	Utility routine to put timestamp on log file.
 *	Caller must hold log file lock.
 */
print_time()
{
	struct timeval	tv;
	struct timezone tz;
	char	*timestring, *scan;

	gettimeofday(&tv, &tz);

	timestring = ctime(&tv.tv_sec);

	scan = timestring;

	while(*scan != '\n')
		scan++;

	*scan = ' ';

	printf("%s", timestring);
}
ents.  Ignore them.
	     */
	    proc_ptr = free_processors;
	    free_processors = proc_ptr->next;
	    proc_ptr->status = BUSY;
	    printf(" %d",proc_ptr->slo./queue.h                                                                                              444     146       0        13311  4756562747   5555                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	queue.h,v $
 * Revision 2.3  91/02/14  14:32:55  mrt
 * 	Changed to new Mach copyright
 * 
 * Revision 2.2  90/01/24  23:33:44  mrt
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	queue.h
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	Queue of abstract objects.  Queue is maintained
 *	within that object.
 *
 *	Supports fast removal from within the queue.
 *
 *	How to declare a queue of elements of type "foo_t":
 *		In the "*foo_t" type, you must have a field of
 *		type "queue_chain_t" to hold together this queue.
 *		There may be more than one chain through a
 *		"foo_t", for use by different queues.
 *
 *		Declare the queue as a "queue_t" type.
 *
 *		Elements of the queue (of type "foo_t", that is)
 *		are referred to by reference, and cast to type
 *		"queue_entry_t" within this module.
 */

/*
 *	A generic doubly-linked list (queue).
 */

struct queue_entry {
	struct queue_entry	*next;		/* next element */
	struct queue_entry	*prev;		/* previous element */
};

typedef struct queue_entry	*queue_t;
typedef	struct queue_entry	queue_head_t;
typedef	struct queue_entry	queue_chain_t;
typedef	struct queue_entry	*queue_entry_t;

/*
 *	Macro:		queue_init
 *	Function:
 *		Initialize the given queue.
 *	Header:
 *		void queue_init(q)
 *			queue_t		q;	/* MODIFIED *\
 */
#define	queue_init(q)	((q)->next = (q)->prev = q)

/*
 *	Macro:		queue_first
 *	Function:
 *		Returns the first entry in the queue,
 *	Header:
 *		queue_entry_t queue_first(q)
 *			queue_t	q;		/* IN *\
 */
#define	queue_first(q)	((q)->next)

/*
 *	Macro:		queue_next
 *	Header:
 *		queue_entry_t queue_next(qc)
 *			queue_t qc;
 */
#define	queue_next(qc)	((qc)->next)

/*
 *	Macro:		queue_end
 *	Header:
 *		boolean_t queue_end(q, qe)
 *			queue_t q;
 *			queue_entry_t qe;
 */
#define	queue_end(q, qe)	((q) == (qe))

#define	queue_empty(q)		queue_end((q), queue_first(q))

/*
 *	Macro:		queue_enter
 *	Header:
 *		void queue_enter(q, elt, type, field)
 *			queue_t q;
 *			<type> elt;
 *			<type> is what's in our queue
 *			<field> is the chain field in (*<type>)
 */
#define queue_enter(head, elt, type, field)			\
{ 								\
	if (queue_empty((head))) {				\
		(head)->next = (queue_entry_t) elt;		\
		(head)->prev = (queue_entry_t) elt;		\
		(elt)->field.next = head;			\
		(elt)->field.prev = head;			\
	}							\
	else {							\
		register queue_entry_t prev;			\
								\
		prev = (head)->prev;				\
		(elt)->field.prev = prev;			\
		(elt)->field.next = head;			\
		(head)->prev = (queue_entry_t)(elt);		\
		((type)prev)->field.next = (queue_entry_t)(elt);\
	}							\
}

/*
 *	Macro:		queue_field [internal use only]
 *	Function:
 *		Find the queue_chain_t (or queue_t) for the
 *		given element (thing) in the given queue (head)
 */
#define	queue_field(head, thing, type, field)			\
		(((head) == (thing)) ? (head) : &((type)(thing))->field)

/*
 *	Macro:		queue_remove
 *	Header:
 *		void queue_remove(q, qe, type, field)
 *			arguments as in queue_enter
 */
#define	queue_remove(head, elt, type, field)			\
{								\
	register queue_entry_t	next, prev;			\
								\
	next = (elt)->field.next;				\
	prev = (elt)->field.prev;				\
								\
	queue_field((head), next, type, field)->prev = prev;	\
	queue_field((head), prev, type, field)->next = next;	\
}

/*
 *	Macro:		queue_assign
 */
#define	queue_assign(to, from, type, field)			\
{								\
	((type)((from)->prev))->field.next = (to);		\
	((type)((from)->next))->field.prev = (to);		\
	*to = *from;						\
}

#define	queue_remove_first(h, e, t, f)				\
{								\
	e = (t) queue_first((h));				\
	queue_remove((h), (e), t, f);				\
}

#define	queue_remove_last(h, e, t, f)				\
{								\
	e = (t) queue_last((h));				\
	queue_remove((h), (e), t, f);				\
}

/*
 *	Macro:		queue_enter_first
 *	Header:
 *		void queue_enter_first(q, elt, type, field)
 *			queue_t q;
 *			<type> elt;
 *			<type> is what's in our queue
 *			<field> is the chain field in (*<type>)
 */
#define queue_enter_first(head, elt, type, field)			\
{ 								\
	if (queue_empty((head))) {				\
		(head)->next = (queue_entry_t) elt;		\
		(head)->prev = (queue_entry_t) elt;		\
		(elt)->field.next = head;			\
		(elt)->field.prev = head;			\
	}							\
	else {							\
		register queue_entry_t next;			\
								\
		next = (head)->next;				\
		(elt)->field.prev = head;			\
		(elt)->field.next = next;			\
		(head)->next = (queue_entry_t)(elt);		\
		((type)next)->field.prev = (queue_entry_t)(elt);\
	}							\
}

/*
 *	Macro:		queue_last
 *	Function:
 *		Returns the last entry in the queue,
 *	Header:
 *		queue_entry_t queue_last(q)
 *			queue_t	q;		/* IN *\
 */
#define	queue_last(q)	((q)->prev)

/*
 *	Macro:		queue_prev
 *	Header:
 *		queue_entry_t queue_prev(qc)
 *			queue_t qc;
 */
#define	queue_prev(qc)	((qc)->prev)

}
}

/*
 *	Compute time until next event.  Make sure it's never negative.
 */

compute_wait_duration()
{
    int delay_time, duration;
    request_t req;

    duration = max_time+1;
    req = queue_first(&time_queue);
    while ((! queue_end(&time_queue, req)) &&
    		(req->state == REQUEST_ASSIGNED)) {
	dela./request.c                                                                                            444     146       0        33406  4754611227   6105                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	request.c,v $
 * Revision 2.3  91/02/08  16:05:28  mrt
 * 	Added new Mach copyright and author notices
 * 
 * Revision 2.2  90/01/24  23:33:47  mrt
 * 	Changed include of sys/error.h to mach/error.h
 * 	[90/01/22            mrt]
 * 
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	request.c
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	Request management
 */
#include <mach.h>
#include <cthreads.h>
#include <mach/error.h>
#include <sys/time.h>

#include <stdio.h>

#include "request.h"

/*
 *	Initialize this module.
 */

void
request_init()
{
    queue_init(&all_requests);
    mutex_init(&all_requests_lock);
    queue_init(&free_requests);
    mutex_init(&free_requests_lock);
    queue_init(&time_queue);
    mutex_init(&time_queue_lock);
    condition_init(&time_queue_condition);
}

/*
 *	Allocate a request.
 */

request_t
request_alloc()
{
    request_t	new_request;
    
    /*
     *	Allocate the data structure.
     */
    mutex_lock(&free_requests_lock);
    if (queue_empty(&free_requests)) {
	new_request = (request_t) malloc(sizeof(struct request));
    }
    else {
	new_request = queue_first(&free_requests);
	queue_remove(&free_requests, new_request, request_t, all_req);
    }
    mutex_unlock(&free_requests_lock);
    
    /*
     *	Initialize the data structure.
     */
    bzero(new_request, sizeof(*new_request));
    port_allocate(task_self(), &new_request->port);
    new_request->state = REQUEST_INACTIVE;
    queue_init(&(new_request->all_req));
    queue_init(&(new_request->active_req));
    mutex_init(&new_request->lock);
    new_request->ref_count = 1;
    new_request->end_notify_done = FALSE;
    new_request->resume_needed = FALSE;

    /*
     *	Insert in all requests list.
     */
    mutex_lock(&all_requests_lock);
    queue_enter(&all_requests, new_request, request_t, all_req);
    mutex_unlock(&all_requests_lock);
    return(new_request);
}

/*
 *	Deallocate request -- free if last reference gone.
 */
request_deallocate(request)
request_t	request;
{
    request_t	prev_request;
    
    request_lock(request);
    if (--(request->ref_count) != 0) {
	request_unlock(request);
    	return;
    }
    /*
     *	This is the last reference, but the convert routine may make
     *	more from the all_requests list.  So put back one reference
     *	and grab the locks in the right order.
     */
    request->ref_count = 1;
    request_unlock(request);

    mutex_lock(&all_requests_lock);
    request_lock(request);
    if (--(request->ref_count) > 0) {
	request_unlock(request);
	mutex_unlock(&all_requests_lock);
	return;
    }

    queue_remove(&all_requests, request,request_t, all_req);
    mutex_unlock(&all_requests_lock);
    request_unlock(request);

    port_set_remove(task_self(), request->port);
    port_deallocate(task_self(), request->port);
    if (request->options & CPU_OPTION_DESTROY)
    	destroy_sets(request);
    
    mutex_lock(&free_requests_lock);
    queue_enter(&free_requests, request, request_t, all_req);
    mutex_unlock(&free_requests_lock);
}

/*
 *	Given a port, convert to a request.  Returns REQUEST_NULL if not
 *	found.  Uses linear list because small number of requests are
 *	expected.
 */

request_t
convert_port_to_request(port)
cpu_request_t	port;
{
    request_t	request;

    mutex_lock(&all_requests_lock);
    request = queue_first(&all_requests);
    while (!queue_end(&all_requests, request)) {
	if (request->port == port && request->state != REQUEST_DEAD) {
	    request_lock(request);
	    request->ref_count++;
	    request_unlock(request);
	    mutex_unlock(&all_requests_lock);
	    return(request);
	}
	request = request->all_req.next;
    }
    mutex_unlock(&all_requests_lock);
    return(REQUEST_NULL);
}

/*
 *	current_time() - return the current time in tenths of seconds
 */
int current_time()
{
    struct timeval	tv;
    struct timezone	tz;

    gettimeofday(&tv,&tz);
    return(tv.tv_sec*10 + tv.tv_usec/100000);
}

/*
 *	request_delay()	- calculate delay on current time queue until
 *		specified request can be honored.  Queue must be locked.
 *		returned delay is in seconds for use by clients.
 */
int request_delay(request)
    request_t	request;
{
    int assigned_delay = 0;
    int activated_delay = 0;
    int this_delay;
    request_t	tmp_request;

    tmp_request = queue_first(&time_queue);

    while (!queue_end(&time_queue, tmp_request) && tmp_request != request) {
    	switch(tmp_request->state) {
	    case REQUEST_ACTIVATED:
	    	activated_delay += tmp_request->run_time;
	    	break;
	    case REQUEST_ASSIGNED:
	    	this_delay = tmp_request->event_time - current_time();
		if (this_delay > assigned_delay)
		    assigned_delay = this_delay;
		break;
	    default:
	    	fprintf(stderr, "Bad request state.\n");
	    	exit(1);
	}
	tmp_request = tmp_request->active_req.next;
    }

    return((assigned_delay + activated_delay)/10);
}

/*
 *	Entry point implementations start here.
 */

mach_error_t
cpu_request_create(server, total_processors, time, delay, cpu_request)
cpu_request_t	server, *cpu_request;
int	total_processors, time, *delay;
{
    request_t	request;

    /*
     *	Argument checks.
     */
    if (server != server_port ||
	(total_processors < MIN_PROCESSORS) ||
        (total_processors > max_processors) ||
	(time < MIN_TIME) ||
	(time > max_time)) {
	    cpu_request = PORT_NULL;
	    return(CPU_INVALID_ARGUMENT);
    }
    request = request_alloc();
    request->total_processors = total_processors;
    request->run_time = time * 10;
    request->total_time = request->run_time;
    *cpu_request = request->port;

    /*
     *	Estimate delay based on current state of time queue.
     */
    mutex_lock(&time_queue_lock);
    *delay = request_delay(request);
    mutex_unlock(&time_queue_lock);

    /*
     *	Add request port to set of ports to receive on.
     */
    port_set_add(task_self(), server_port_set, request->port);

    return (CPU_SUCCESS);
}

/*
 *	Add a processor set + processors to a request.
 */

mach_error_t
cpu_request_add(cpu_request, processor_set, processors, processors_left)
cpu_request_t	cpu_request;
processor_set_t	processor_set;
int	processors, *processors_left;
{
	request_t	request;
	mach_error_t	ret;

	if ((request = convert_port_to_request(cpu_request)) ==
	    REQUEST_NULL) {
		ret = CPU_INVALID_ARGUMENT;
		return(ret);
	}

	request_lock(request);

	if (processors <= 0) {
	    ret = CPU_INVALID_ARGUMENT;
	    goto done;
	}

	if ((request->set_count == MAX_SETS) ||
	    (request->total_processors - request->assigned_processors <
	     processors)) {
		ret = CPU_LIMIT_EXCEEDED;
		goto done;
	}

	if (request->state != REQUEST_INACTIVE) {
		ret = CPU_REQUEST_ACTIVE;
		goto done;
	}
	
	request->sets[request->set_count] = processor_set;
	request->processors[request->set_count] = processors;
	request->set_count += 1;
	request->assigned_processors += processors;
	*processors_left = request->total_processors -
		request->assigned_processors;
	
	ret = CPU_SUCCESS;
done:
	request_unlock(request);
	request_deallocate(request);
	return(ret);
}

/*
 *	cpu_request_activate_common - Common code for request activation.
 */
mach_error_t
cpu_request_activate_common(cpu_request, options, total_time, delay, task)
cpu_request_t	cpu_request;
int		options;
int		total_time;
int		*delay;
{
	request_t	request, prev_req;
	mach_error_t	ret;

	if (((options & CPU_OPTION_REPEAT) &&
		((total_time < MIN_TIME ) ||
		 (total_time > max_total_time))) ||
	    (request = convert_port_to_request(cpu_request)) ==
		REQUEST_NULL) {
			ret = CPU_INVALID_ARGUMENT;
			return(ret);
	}

	mutex_lock(&time_queue_lock);
	request_lock(request);

	if (request->state != REQUEST_INACTIVE) {
		ret = CPU_REQUEST_ACTIVE;
		goto done;
	}

	request->state = REQUEST_ACTIVATED;
	request->options |= options;
	request->task = task;
	request->total_processors = request->assigned_processors;
	request->assigned_processors = 0;
	if (options & CPU_OPTION_REPEAT) {
		request->total_time = total_time * 10;
		if (request->run_time > request->total_time)
			request->run_time = request->total_time;
	}

	/*
	 *	Insert request into time queue.
	 */
	queue_enter(&time_queue, request, request_t, active_req);
	*delay = request_delay(request);

	/*
	 * If this is the first request on the time queue, unblock the time
	 * thread to deal with it.
	 */
	if (request == queue_first(&time_queue)) {
		condition_signal(&time_queue_condition);
	}
	else {

	    /*
	     * If this is the first unassigned request and there are enough
	     * processors available, wake up the time thread to assign them.
	     */
	    prev_req = (request_t) request->active_req.prev;
	    if ((prev_req->state == REQUEST_ASSIGNED) &&
	    	(available_processors >= request->total_processors)) {
		  abort_wait();
	    }
	}

	ret = CPU_SUCCESS;

done:
	request_unlock(request);
	mutex_unlock(&time_queue_lock);
	request_deallocate(request);
	mutex_lock(&log_file_lock);
	print_time();
    	printf("Activated %d: %d processors\n", (int)request,
		request->total_processors);
	fflush(stdout);
    	mutex_unlock(&log_file_lock);
	return(ret);
}

/*
 *	Actual stubs that call cpu_request_activate_common.
 */
mach_error_t
cpu_request_activate(cpu_request, options, total_time, delay)
cpu_request_t	cpu_request;
int		options;
int		total_time;
int		*delay;
{
	return(cpu_request_activate_common(cpu_request,
		options & CPU_VALID_OPTIONS,
		total_time, delay, (task_t)0));
}

mach_error_t
cpu_request_activate_task(cpu_request, options, total_time, task, delay)
cpu_request_t	cpu_request;
int		options;
int		total_time;
task_t		task;
int		*delay;
{
	return(cpu_request_activate_common(cpu_request,
		(options & CPU_VALID_OPTIONS) | CPU_OPTION_SUSPEND,
		total_time, delay, task));
}

/*
 *	cpu_request_set_notify: indicate that request generates
 *	notifications and supply a port for them.
 */
mach_error_t
cpu_request_set_notify(cpu_request, notify_port)
cpu_request_t	cpu_request;
port_t		notify_port;
{
	request_t	request;
	mach_error_t	ret = ERR_SUCCESS;

	if ((request = convert_port_to_request(cpu_request)) ==
	    REQUEST_NULL) {
		return(CPU_INVALID_ARGUMENT);
	}
	request_lock(request);

	if (request->state == REQUEST_INACTIVE) {
		request->options |= CPU_OPTION_NOTIFY;
		request->notify_port =  notify_port;
	}
	else {
		ret = CPU_REQUEST_ACTIVE;
	}

	request_unlock(request);
	request_deallocate(request);
	return(ret);
}

	

/*
 *	cpu_request_destroy - terminate a cpu request.
 */
mach_error_t
cpu_request_destroy(cpu_request)
cpu_request_t	cpu_request;
{
	request_t	request;

	if ((request = convert_port_to_request(cpu_request)) ==
	    REQUEST_NULL) {
		return(CPU_INVALID_ARGUMENT);
	}

    	mutex_lock(&time_queue_lock);
	request_lock(request);
	switch(request->state) {
	    case REQUEST_ASSIGNED:
	       /*
		* Bring this request to the head of the time queue.
		*/
		queue_remove(&time_queue, request, request_t, active_req);
		queue_enter_first(&time_queue, request, request_t,
			active_req);
	       /*
	    	* Killing the request.  Make it appear to have timed out.
		* If an end notification was requested, this will be
		* handled as usual by the time thread.
	     	*/
	    	request->event_time = current_time();
		request->total_time = request->run_time;
	    	abort_wait();   /* abort timeout */
	    	request_unlock(request);
	    	break;
	    case REQUEST_ACTIVATED:
		queue_remove(&time_queue, request, request_t, active_req);
	       /*
	        * Fall through...
		*/
	    case REQUEST_INACTIVE:
		request_unlock(request);
		request_deallocate(request);
		break;
	    case REQUEST_DEAD:
	        request_unlock(request);
		break;
	    default:
	    	fprintf(stderr, "cpu_request_destroy: bad state.\n");
		exit(1);
	}
    	mutex_unlock(&time_queue_lock);
	
	request_deallocate(request);
	return(CPU_SUCCESS);
}

/*
 *	cpu_request_status - return info on a request.
 */

mach_error_t
cpu_request_status(cpu_request, reserved, assigned, active, options, time)
cpu_request_t	cpu_request;
int	*reserved, *assigned;
boolean_t	*active;
int	*options, *time;
{
	request_t	request;

	if ((request = convert_port_to_request(cpu_request)) ==
	    REQUEST_NULL) {
		return(CPU_INVALID_ARGUMENT);
	}

	mutex_lock(&time_queue_lock);
	request_lock(request);
	*reserved = request->total_processors;
	*assigned = request->assigned_processors;
	*time = request_delay(request);
	if (request->state == REQUEST_INACTIVE) {
	    *active = FALSE;
	    *options = CPU_OPTION_NONE;
	}
	else {
	    *active = TRUE;
	    *options = request->options;
	}
	request_unlock(request);
	mutex_unlock(&time_queue_lock);

	request_deallocate(request);

	return(CPU_SUCCESS);
}

/*
 *	Generic information about server.
 */
mach_error_t
cpu_server_info(server, time, total_time, processors, delay)
port_t	server;
int	*time, *total_time, *processors, *delay;
{
	*time = max_time;
	*total_time = max_total_time;
	*processors = max_processors;
	mutex_lock(&time_queue_lock);
	*delay = request_delay(REQUEST_NULL);
	mutex_unlock(&time_queue_lock);

	return(CPU_SUCCESS);
}
    }

    return((assigned_delay + activated_delay)/10);
}

/*
 *	Entry point implementations start here.
 */

mach_error_t
cpu_request_create(server, total_processors, time, delay, cpu_request)
cpu_request_t	server, *cpu_request;
int	total_processo./request.h                                                                                            444     146       0         7127  4756562753   6106                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	request.h,v $
 * Revision 2.3  91/02/14  14:33:00  mrt
 * 	Changed to new Mach copyright
 * 
 * Revision 2.2  90/01/24  23:33:52  mrt
 * 	Changed include of kern/mach_types.h to mach/mach_types.h
 * 	[90/01/22            mrt]
 * 
 * 	Created
 * 	[90/01/18            dlb]
 * 
 */
/*
 *	File: 	request.h
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	Request type definitions.
 */

#include <mach/mach_types.h>
#include <cthreads.h>
#include "queue.h"

#include "assign.h"
#include "cpu_server.h"

#define	MAX_SETS	64		/* max sets in a request */

struct	request {
    	queue_chain_t	all_req;		/* doubly linked list */
	queue_chain_t	active_req;		/* another d-l list */
	cpu_request_t	port;			/* corresponding port */
	int		total_processors;	/* total requested */
	run_processor_t	processor_ids;		/* processor ids */
	int		set_count;		/* sets involved */
	processor_set_t	sets[MAX_SETS];		/* the sets themselves */
	int		assigned_processors;	/* assignment requests */
	int		processors[MAX_SETS];	/* corresponding requests */
	int		options;		/* options for this request */
	int		run_time;		/* elapsed time requested */
	int		total_time;		/* total time to consume */
	int		event_time;		/* time of next event */
	int		state;			/* current state */
	port_t		notify_port;		/* port for client notify */
	boolean_t	end_notify_done;	/* final notify done ? */
	task_t		task;			/* task to suspend */
	boolean_t	resume_needed;		/* resume needed on assign? */
	struct mutex	lock;			/* cthreads lock */
	int		ref_count;		/* reference count */
};

typedef	struct request		request_data_t;
typedef struct request		*request_t;

/*
 *	State definitions
 */

#define	REQUEST_INACTIVE	0
#define REQUEST_ACTIVATED	1
#define	REQUEST_ASSIGNED	2
#define REQUEST_DEAD		3

/*
 *	NOTE: times in client interface are in seconds, internal times
 *	are in tenths.
 */

/*
 *	List of all requests
 */

queue_head_t	all_requests;
struct mutex	all_requests_lock;

queue_head_t	free_requests;
struct mutex	free_requests_lock;

#define REQUEST_NULL	(request_t)0

#define request_lock(request)	mutex_lock(&request->lock)
#define request_unlock(request)	mutex_unlock(&request->lock)

/*
 *	queue of requests with times.
 */

queue_head_t	time_queue;
struct mutex	time_queue_lock;
struct condition time_queue_condition;

thread_t	time_thread;

struct mutex	log_file_lock;	/* both threads log information */

/*
 *	Useful ports
 */
 
port_t	server_port;
port_set_name_t	server_port_set;

/*
 *	Internal options.  Clients invoke these by calling different
 *	interface routines.
 */

#define CPU_OPTION_NOTIFY	0x4
#define CPU_OPTION_SUSPEND	0x8
MAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * H./task_special_user.c                                                                                  444     146       0         7106  4754611235  10072                                                                                                                                                                                                                                                                                                                                                                      /*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	task_special_user.c,v $
 * Revision 2.3  91/02/08  16:05:34  mrt
 * 	Added new Mach copyright and author notices
 * 
 * Revision 2.2  90/01/24  23:33:55  mrt
 * 	Changed include of mach/mach_interface.h to mach_interface.h
 * 	[90/01/22            mrt]
 * 
 * 	Updated to reflect new mig.
 * 	[89/08/04            dlb]
 * 
 * 	Created
 * 	[89/03/11            dlb]
 * 
 */
/*
 *	File: 	task_special_user.c
 *	Author:	David Black, Carnegie Mellon University
 *	Date:	Jan 1990
 *
 *	Special versions of task_{suspend,resume} cut down from mach_user.c.
 *	These versions are modified in two ways to protect servers from
 *	users who supply bogus ports:
 *		1.  There is no reply message requested or expected.
 *		2.  There is a send timeout of 0.
 *	This works fine for the expected usage case: server performing
 *	operations on tasks on the LOCAL machine.  This should not be used
 *	if the task may be remote!
 */

#include <mach_interface.h>
#include <mach/message.h>
#include <mach/mach_types.h>
#include <mach/mig_errors.h>
#include <mach/msg_type.h>

#ifndef	TypeCheck
#define	TypeCheck 1
#endif	TypeCheck

#ifndef	UseExternRCSId
#if	hc
#define	UseExternRCSId		1
#endif	hc
#endif	UseExternRCSId

#ifndef UseStaticMsgType
#if     !defined(hc) || defined(__STDC__)
#define UseStaticMsgType        1
#endif
#endif

/* Routine task_suspend_special */
mig_external kern_return_t task_suspend_special(
#if     (defined(__STDC__) || defined(c_plusplus))
		task_t target_task)
#else
	target_task)
		task_t target_task;
#endif
{
	typedef struct {
		msg_header_t Head;
	} Request;

	union {
		Request In;
	} Mess;

	register Request *InP = &Mess.In;

	msg_return_t msg_result;

	InP->Head.msg_simple = TRUE;
	InP->Head.msg_size = sizeof(Request);
	InP->Head.msg_type = MSG_TYPE_NORMAL;
	InP->Head.msg_remote_port = target_task;
	InP->Head.msg_local_port = PORT_NULL;
	InP->Head.msg_id = 2056;

	msg_result = msg_send(&InP->Head, SEND_TIMEOUT, 0);

	return(msg_result);
}

/* Routine task_resume_special */
mig_external kern_return_t task_resume_special(
#if     (defined(__STDC__) || defined(c_plusplus))
		task_t target_task)
#else
	target_task)
		task_t target_task;
#endif
{
	typedef struct {
		msg_header_t Head;
	} Request;

	union {
		Request In;
	} Mess;

	register Request *InP = &Mess.In;

	msg_return_t msg_result;

	InP->Head.msg_simple = TRUE;
	InP->Head.msg_size = sizeof(Request);
	InP->Head.msg_type = MSG_TYPE_NORMAL;
	InP->Head.msg_remote_port = target_task;
	InP->Head.msg_local_port = PORT_NULL;
	InP->Head.msg_id = 2057;

	msg_result = msg_send(&InP->Head, SEND_TIMEOUT, 0);

	return(msg_result);
}
*time = request_delay(request);
	if (request->state == REQUEST_INACTIVE) {
	    *active = FALSE;
	    *options = CPU_OPTION_NONE;
	}
	else {
	    *active = TRUE;
	    *options = request->options;
	}
	request_unlock(request);
	mutex_unlock(&time_queue_lock);

	request_deallocate(request);

	return(CPU_SUCCESS);
}

/*
 *	Generic information about server.
 */
mach_error_t
cpu_server_info(server, time, total_time, processors, delay)
port_t	se./Make.inc                                                                                             644     146       0        15276  4665041717   5632                                                                                                                                                                                                                                                                                                                                                                      # 
# Mach Operating System
# Copyright (c) 1989 Carnegie-Mellon University
# All rights reserved.  The CMU software License Agreement specifies
# the terms and conditions for use and redistribution.
#
# HISTORY
# $Log:	Make.inc,v $
# Revision 1.10  90/04/10  17:48:54  mrt
# 	Changed default flags to mach_install to include -s (strip)
# 	Changed rule for I so that it can be overriden in local Makefilex
# 	Added sun4 definitions
# 	[90/02/11            mrt]
# 
# Revision 1.9  90/01/24  22:50:52  mrt
# 	Added rules for LaTeX documents and rule to install .doc
# 	documents.
# 	[90/01/08            mrt]
# 
# Revision 1.8  90/01/08  13:56:14  mrt
# fixed up rules for LaTex documents and .doc installs.
# 
# Revision 1.7  89/08/28  16:03:01  mrt
# 		Added definition for PMAX_M. Added definitions for
# 		$(MACHINE)_AS_FLAGS
# 		Removed do_doc_mans and do_install_doc_mans rules. Renamed
# 		PS to ps, and added scribe rule to build .doc as well as 
# 		.ps files.
# 	[89/08/28            mrt]
# 
# Revision 1.6  89/07/28  13:58:12  mrt
# 	Added definition of MMAX_CCA.
# 	[89/07/28            mrt]
# 
# Revision 1.5  89/07/14  16:58:24  mrt
# 	Changed to work better with build. INSTALL targets no
# 	longer depend on ALL as build will do that for the -fromsource
# 	builds. Do not export CPATH and LPATH.
# 	[89/06/22            mrt]
# 
# Revision 1.4  89/06/08  17:57:52  mrt
# 	Changed the csh and sh.install to install the scripts
# 	with execute permission.
# 	[89/06/08            mrt]
# 
# Revision 1.3  89/06/07  16:02:54  mrt
# 	Added _CCFLAGS_ which are the union of DEF_CFLAGS, CFLAGS,
# 	CARGS and CENV. Added CC_W_ASM which is a compiler that
# 	understands .asm statements (e.g. not hc). Separated INSTALL_LIB
# 	and INSTALL_LIBP.
# 	[89/06/07            mrt]
# 
#

INCDIR=$(DSTBASE)/include

SERVERINCDIR=$(INCDIR)/servers
LIBMACH=$(DSTBASE)/lib/libmach.a
LIBTHREADS = $(DSTBASE)/lib/libthreads.a
LIBCPU = $(DSTBASE)/lib/libcpu.a
DEP_FILE = ./Makedep

MIGFLAGS 	= -MD 
VAX_M=$(machine)
IBMRT_M=$(machine)
SUN_M=sun3
SUN4_M=$(machine)
PMAX_M=pmax

STRIP = ${NO_STRIP?"":-s}
DEF_I_FLAGS		= -c -d 
I=${I_FLAGS?${I_FLAGS}:${DEF_I_FLAGS}}
DEF_CFLAGS=${DEF_CFLAGS?${DEF_CFLAGS}:-O -MD -DMACH -D$($(MACHINE)_M)}
_CCFLAGS_=${$@_CFLAGS?${$@_CFLAGS}:${CFLAGS}} ${$@_CENV?${$@_CENV}:${CENV}} ${$@_CARGS?${$@_CARGS}:${CARGS}} ${$@_DEF_CFLAGS?${$@_DEF_CFLAGS}:${DEF_CFLAGS}}

VAX_AS_FLAGS=
SUN3_AS_FLAGS=
SUN4_AS_FLAGS=
IBMRT_AS_FLAGS=
MMAX_AS_FLAGS=
PMAX_AS_FLAGS=-nocpp
CC=${CC?${CC}:cc}
VAX_CCA=${CC}
SUN_CCA=${CC}
SUN4_CCA=${CC}
MMAX_CCA=${CC}
IBMRT_CCA=pcc
PMAX_CCA=$(CC)
CC_W_ASM=${${MACHINE}_CCA}

_INCDIR=${${@:.install=}_INCDIR?${${@:.install=}_INCDIR}:${INCDIR}}
_INSTALL_DIR=${${@:.install=}_INSTALL_DIR?${${@:.install=}_INSTALL_DIR}:${INSTALL_DIR}}

RELEASE=release
IOWNER=${IOWNER?${IOWNER}:mach}
IGROUP=${IGROUP?${IGROUP}:mach}
IMODE=${IMODE?${IMODE}:755}

INSTALLING=${FROMBASE?x:install}
RELEASING=${FROMBASE?install:x}

OBJS		= $(SRCS:.c=.o)
MIG_HDRS	= $(DEFS:.defs=.h)
MIG_USRS	= $(DEFS:.defs=User.c) 
MIG_SRVS	= $(DEFS:.defs=Server.c) 
USR_OBJS	= $(DEFS:.defs=User.o) 
SRV_OBJS	= $(DEFS:.defs=Server.o) 
DOC_OBJS	= $(DOC:=.ps) $(DOC:=.doc)
DOC_MSS_OBJS	= $(FSRC:.fsrc=.mss)
LIB_OBJS	= $(LIB_SRCS:.c=.o)
INSTALL_INCS	= $(INCS:=.install)
INSTALL_DOCS	= $(DOC:=.install) $(TDOC:=.install)
INSTALL_OBJS	= $(PRGM:=.${INSTALLING})  $(PRGM1:=.${INSTALLING})  $(PRGM1L:=.${INSTALLING})
RELEASE_OBJS	= $(PRGM:=.${RELEASING})  $(PRGM1:=.${RELEASING})  $(PRGM1L:=.${RELEASING})
INSTALL_CSHS	= $(CSH:.csh=.install) $(CSH:.sh=.install)
INSTALL_MANS	= $(MAN_OBJS:.${SECTION}=.install)
INSTALL_LIB	= $(LIB_BLD:=.install)
INSTALL_LIBP	= $(LIBP_BLD:=.install)
MIG_OUTPUTS	= $(MIG_HDRS) $(MIG_USRS) $(MIG_SRVS)
SUB_DIR		= $(SUBS:=/dir)
SUB_ALL		= $(SUBS:=/all)
SUB_INSTALL	= $(SUBS:=/install)
FORCE		= xxFUNNYxx.force

.SUFFIXES: .mss .fsrc .ps .install .csh .sh .$(SECTION)

.fsrc.mss:
	format $*.fsrc

.c.o:
	$(CC) $(_CCFLAGS_) -c $*.c
	md -u $(DEP_FILE) -d $*.d

.csh.install:
	-@mach_install ${I} -m 555 $*.csh ${INSTALL_DIR}/$*
	-@touch $*.install

.sh.install:
	-mach_install ${I} -m 555 $*.sh ${INSTALL_DIR}/$*
	-touch $*.install

.$(SECTION).install:
	-@mach_install ${I} $*.$(SECTION) ${INSTALL_MAN_DIR}
	-@touch $*.install

all:	$(TARGET_DIRS) $(SUB_DIR) $(SUB_ALL) $(PRGM) $(PRGM1) $(PRGM1L) \
 	 $(LIB_BLD) $(LIBP_BLD) $(DOC_OBJS) 

include: $(TARGET_DIRS) $(INSTALL_INCS)


install: $(TARGET_DIRS) $(SUB_DIR) $(SUB_INSTALL) $(INSTALL_INCS) \
	 $(INSTALL_OBJS) $(INSTALL_DOCS) \
	 $(INSTALL_CSHS) $(INSTALL_LIB) $(INSTALL_LIBP) $(INSTALL_MANS) 
do_toc:
	catman -M $(INSTALL_MAN_DIR)/.. $(SECTION)


$(TARGET_DIRS):
	mkdir $@


$(SUB_ALL) $(SUB_INSTALL): $(FORCE)
	-cd $(@D) && $(MAKE) $(MFLAGS) DSTBASE=$(DSTBASE)\
	 SRCBASE=$(SRCBASE) LIBMACH=$(LIBMACH) \
	 LIBTHREADS=$(LIBTHREADS)  $(@F)

$(SUB_DIR):
	-@if [ ! -d $(@D) ]; then echo "mkdir ./$(@D)" ; \
	mkdir ./$(@D) ;\
	else true; fi

$(FORCE):

#.EXPORT: CPATH LPATH PATH

$(PRGM):  $(SRV_OBJS) $(OBJS) $(LIBS)
	-$(CC) $(_CCFLAGS_) -o $(PRGM) $(OBJS) $(SRV_OBJS) $(LIBS)

$(PRGM1L): $$@.o $(LIBS)
	-$(CC)  $(_CCFLAGS_) -o $@  $@.o $(LIBS)

$(PRGM1): $$@.o
	-$(CC)  $(_CCFLAGS_) -o $@  $@.o 

$(DOC_MSS_OBJS): $$(@:.mss=.fsrc)

$(DOC_OBJS): $(MSS)
	scribe $* -device:postscript
	scribe $* -device:file

$(LIB_BLD) : $(LIB_OBJS)
	@rm -f $(LIB_BLD)
	ar crv ${LIB_BLD} ${LIB_OBJS} 
	ranlib ${LIB_BLD}

$(LIBP_BLD) : $(LIB_OBJS)
	@rm -f profiled/$(LIBP_BLD)
	if [ -d profiled ]; then true; \
	else mkdir profiled; fi;
	cd profiled && ar crv ${LIBP_BLD} ${LIB_OBJS} 
	ranlib profiled/${LIBP_BLD}
	mv profiled/${LIBP_BLD} .

$(INSTALL_INCS): $$(@:.install=)
	-mach_install ${I} $(@:.install=) $(_INCDIR)
	-@touch $@

$(INSTALL_OBJS): $$(@:.install=)
	-mach_install ${I} ${STRIP} $(@:.install=) $(_INSTALL_DIR)
	-@touch $@

$(RELEASE_OBJS):
	${_RELEASE_} -o ${%_IOWNER?${%_IOWNER}:${IOWNER}}\
		-g ${%_IGROUP?${%_IGROUP}:${IGROUP}}\
		-m ${%_IMODE?${%_IMODE}:${IMODE}}\
		-tostage ${TOSTAGE}\
		-fromstage ${FROMSTAGE}\
		${_INSTALL_DIR}/%


$(INSTALL_DOCS): $(DOC_OBJS)
	-@mach_install ${I} $? $(INSTALL_DIR)
	-@touch $@

$(INSTALL_MANS): $$(@:.install=.$(SECTION)
#	-@mach_install ${I} $(@:.install=.$(SECTION)) $(INSTALL_MAN_DIR)
#	-@touch $@

$(INSTALL_LIB): $(LIB_BLD)
	-@mach_install ${I} -r $(LIB_BLD) $(INSTALL_DIR)
	-@touch $@

$(INSTALL_LIBP): $(LIBP_BLD)
	-@ mach_install ${I} -r $(LIBP_BLD) $(INSTALL_DIR)
	-@touch $@

$(MIG_HDRS): $$(@:.h=.defs)
	mig $(MIGFLAGS) $(MIGENV) $(MIGARGS) $(@:.h=.defs) \
	   -server /dev/null -user /dev/null
	md -u $(DEP_FILE) -d $(@:.h=.d)

$(MIG_USRS): $$(@:User.c=.defs)
	mig $(MIGFLAGS)  $(MIGENV) $(MIGARGS) $(@:User.c=.defs)
	md -u $(DEP_FILE) -d $(@:User.c=.d)

$(MIG_SRVS): $$(@:Server.c=.defs)
	mig $(MIGFLAGS)  $(MIGENV) $(MIGARGS) $(@:Server.c=.defs)
	md -u $(DEP_FILE) -d $(@:Server.c=.d)

-include $(OBJECTDIR)/$(DEP_FILE)

ocessors) ||
	(time < MIN_TIME) ||
	(time > max_time)) {
	    cpu_request = PORT_NULL;
	    return(CPU_INVALID_ARGUMENT);
    }
    request = request_alloc();
    request->total_processors = total_processors;
    request->run_time = time * 10;
    request->total_time = request->run_time;
    *cpu_request = request->port;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                # 
# Mach Operating System
# Copyright (c) 1989 Carnegie-Mellon University
# All rights reserved.  The CMU software License Agreement specifies
# the terms and conditions for use and redistribution.
#
# HISTORY
# $Log:	Make.inc,v $
# Revision 1.10  90/04/10  17:48:54  mrt
# 	Changed default flags to mach_install to include -s (strip)
# 	Changed rule for I so that it can be overriden in local Makefilex
# 	Added sun4 definitions
# 	[90/02/11            mrt]
# 
# Revision 1.9  90/01/24  22:50:52  mrt
# 	Added rules for LaTeX documents and rule to install .doc
# 	documents.
# 	[90/01/08            mrt]
# 
# Revision 1.8  90/01/08  13:56:14  mrt
# fixed up rules for LaTex documents and .doc installs.
# 
# Revision 1.7  89/08/28  16:03:01  mrt
# 		Added definition for PMAX_M. Added definitions for
# 		$(MACHINE)_AS_FLAGS
# 		Removed do_doc_mans and do_install_doc_mans rules. Renamed
# 		PS to ps, and added scribe rule to build .doc as well as 
# 		.ps files.
# 	[89/08/28            mrt]
# 
# Revision 1.6  89/07/28  13:58:12  mrt
# 	Added definition of MMAX_CCA.
# 	[89/07/28            mrt]
# 
# Revision 1.5  89/07/14  16:58:24  mrt
# 	Changed to work better with build. INSTALL targets no
# 	longer depend on ALL as build will do that for the -fromsource
# 	builds. Do not export CPATH and LPATH.
# 	[89/06/22            mrt]
# 
# Revision 1.4  89/06/08  17:57:52  mrt
# 	Changed the csh and sh.install to install the scripts
# 	with execute permission.
# 	[89/06/08            mrt]
# 
# Revision 1.3  89/06/07  16:02:54  mrt
# 	Added _CCFLAGS_ which are the union of DEF_CFLAGS, CFLAGS,
# 	CARGS and CENV. Added CC_W_ASM which is a compiler that
# 	understands .asm statements (e.g. not hc). Separated INSTALL_LIB
# 	and INSTALL_LIBP.
# 	[89/06/07            mrt]
# 
#

INCDIR=$(DSTBASE)/include

SERVERINCDIR=$(INCDIR)/servers
LIBMACH=$(DSTBASE)/lib/libmach.a
LIBTHREADS = $(DSTBASE)/lib/libthreads.a
LIBCPU = $(DSTBASE)/lib/libcpu.a
DEP_FILE = ./Makedep

MIGFLAGS 	= -MD 
VAX_M=$(machine)
IBMRT_M=$(machine)
SUN_M=sun3
SUN4_M=$(machi