Source to osfmk/kern/sf.h


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @[email protected]
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @[email protected]
 */
/*
 * @[email protected]
 * 
 */

#ifndef	_KERN_SF_H_
#define _KERN_SF_H_

/*
 * The calls most likely to change are: policy_thread_done and
 * policy_thread_begin.  They're the policy calls related to 
 * context switching. I'm not satisfied with what I have now and
 * these are the forms I'm trying next.
 * 
 * I still have to merge the data type names from my different sandboxes
 * and I don't really talk about locking except for the run queue locking.
 * 
 * A good example of the data type problem is sched_thread_t and thread_t.
 * Right now, they're equivalent BUT eventually, i expect that policies
 * will only use sched_thread_t which will only contain the scheduling
 * attributes and the framework will know how to convert sched_thread_t
 * to thread_t (policy-mechanism seperation).
 * 
 * There is a big change for run queues: there is a single lock for an
 * entire run queue array structure (instead of a lock per queue header).
 * It's OK for a policy to reorganize a particular queue BUT it has to
 * disable the queue header (sched_queue_disable).  Since a queue header
 * isn't shared by multiple policies and the framework won't touch the
 * queue header if it's disabled, the policy can do anything it wants
 * without taking out a global lock.
 * 
 * The only run queue primitives provided are the really fast ones:
 * insert at the head (sched_queue_preempt), insert at the tail
 * and if the queue was empty check for preemption 
 * (sched_queue_add_preempt), just insert at the tail
 * (sched_queue_add_only), and remove (sched_queue_remove).  Everything
 * else needs to be done by first disabling the queue header (and then
 * you can do whatever you want to the queue).
 * 
 * BTW, the convention here is:
 * 
 *    policy_xxx - calls from the framework into policies (via the
 * 	pointers in the policy object)
 * 
 *    sched_xxx - scheduling mechanisms provided by the framework
 *         which can be called by policies.
 * 
 * ----------
 * 
 * Initializes an instance of a scheduling policy assigning it the
 * corresponding policy_id and run queue headers.
 * 
 * policy_init(
 *     sched_policy_object	 *policy,
 *     int policy_id,				/ * policy number * /
 *     int priority_mask_length,			/ * length of a priority mask * /
 *     sched_priority_mask *priority_mask );	/ * mask for this policy * /
 * 
 * Enable/disable a scheduling policy on a processor [set]
 * 
 * policy_enable_processor_set(
 *     sched_policy_object *policy,		/ * policy * /
 *     processor_set_t processor_set );		/ * processor set * /
 * 
 * policy_disable_processor_set(
 *     sched_policy_object *policy,
 *     processor_set_t processor_set);
 * 
 * policy_enable_processor(
 *     sched_policy_object *policy,		/ * policy * /
 *     processor_t processor );			/ * processor set * /
 * 
 * policy_disable_processor(
 *     sched_policy_object *policy,
 *     processor_t processor);
 * 
 * Notifies the policy that the thread has become runnable
 * 
 * policy_thread_unblock(
 *     sched_policy_object *policy,
 *     sched_thread_t thread )
 * 
 * Notifies the policy that the current thread is done or
 * a new thread has been selected to run
 * 
 * policy_thread_done(
 *     sched_policy_object *policy,
 *     sched_thread_t *old_thread );
 * 
 * policy_thread_begin(
 *     sched_policy_object *policy,
 *     sched_thread_t *new_thread );
 * 
 * Attach/detach a thread from the scheduling policy
 * 
 * policy_thread_attach(
 *     sched_policy_object *policy,
 *     sched_thread_t *thread );
 * 
 * policy_thread_detach(
 *     sched_policy_object *policy,
 *     sched_thread_t *thread );
 * 
 * Set the thread's processor [set]
 * 
 * policy_thread_processor(
 *     sched_policy_object *policy,
 *     sched_thread_t *thread,
 *     processor_t processor );
 * 
 * policy_thread_processor_set(
 *     sched_policy_object *policy,
 *     sched_thread_t *thread,
 *     processor_set_t processor_set);
 * 
 * Set/get a thread's scheduling attributes
 * 
 * policy_thread_set(
 *     sched_policy_object *policy,
 *     sched_thread_t thread,
 *     sched_policy_attributes policy_attributes);
 * 
 * policy_thread_get(
 *     sched_policy_object *policy,
 *     sched_thread_t thread,
 *     sched_policy_attributes *policy_attributes);
 * 
 * Scheduling Framework Interfaces
 * 
 * [en/dis]able particular run queue headers on a processor [set],
 * 
 * Lock the run queues, update the mask, unlock the run queues.  If
 * enabling, check preemption.
 * 
 * sched_queue_enable(
 *     run_queue_t		runq,
 *     sched_priority_mask *mask );
 * 
 * sched_queue_disable(
 *     run_queue_t		runq,
 *     sched_priority_mask *mask );
 * 
 * Lock the run queues, insert the thread at the head, unlock the
 * run queues and preempt (if possible).
 * 
 * sched_queue_preempt(
 *     meta_priority_t	priority,
 *     thread_t		thread,
 *     run_queue_t		run_queues );
 * 
 * Lock the run queues, add the thread to the tail, unlock the run queues
 * and preempt if appropriate.
 * 
 * sched_queue_add_preempt(
 *     meta_priority_t	priority,
 *     thread_t		thread,
 *     run_queue_t		run_queues );
 * 
 * Lock the run queues, add the thread to the tail, unlock the queues
 * but don't check for preemption.
 * 
 * sched_queue_add_only(
 *     meta_priority_t	priority,
 *     thread_t		thread,
 *     run_queue_t		run_queues );
 * 
 * Lock the run queues, remove the entry the thread, unlock the run queues.
 * 
 * sched_queue_remove(
 *     thread_t		thread );
 */

#include <kern/kern_types.h>
#include <kern/sched.h>
#include <mach/thread_switch.h>
#include <mach/mach_types.h>

/*
 * Type definitions and constants for MK Scheduling Framework
 */
typedef int	sf_return_t;

/* successful completion */
#define SF_SUCCESS					0

/* error codes */
#define SF_FAILURE					1
#define SF_KERN_RESOURCE_SHORTAGE	2

/* Scheduler Framework Object -- i.e., a scheduling policy */
typedef struct sf_policy	*sf_object_t;

/* Scheduler Framework thread definition is just a thread (for now) */
typedef thread_t			sched_thread_t;

/* Scheduler Framework priority mask definition */
typedef struct {
	int bitmap[NRQBM];
} sf_priority_mask, *sf_priority_mask_t;

/* Scheduler Framework meta-priority definition is just an int (for now) */
typedef int	meta_priority_t;

/**********
 *
 * Scheduling Attributes
 *
 **********/

struct sp_attributes {
	int			policy_id;	/* index of SP for kernel */
};

typedef int	sp_attributes_size_t;

#define SP_ATTRIBUTES_NULL	((sp_attributes_t) 0)

/**********
 *
 * Scheduling Information
 *
 **********/

/*** ??? typedef void	*sp_info_t; ***/
typedef int	sp_info_size_t;

#define SP_INFO_NULL		((sp_info_t) 0)

/*
 * maximum number of scheduling policies that the Scheduling Framework
 * will host (picked arbitrarily)
 */
#define MAX_SCHED_POLS		( 10 )

/**********
 *
 * Scheduling Framework Interfaces
 *
 **********/

/* Initialize Framework and selected policies */
void		sf_init(void);

/* [En/Dis]able particular run queue headers on a processor [set] */

/* Lock run queues, update mask, unlock run queues.  If enabling, check preemption */
sf_return_t	(*sf_queue_enable)(
		    run_queue_t		runq,
		    sf_priority_mask	*mask);

sf_return_t	(*sf_queue_disable)(
		    run_queue_t		runq,
		    sf_priority_mask	*mask);

/* Lock run queues, insert thread at head, unlock run queues and preempt (if possible) */
sf_return_t	(*sf_queue_preempt)(
		    meta_priority_t	priority,
		    thread_t		thread,
		    run_queue_t		run_queues);

/* Lock run queues, add thread to tail, unlock run queues and preempt if appropriate */
sf_return_t	(*sf_queue_add_preempt)(
		    meta_priority_t	priority,
		    thread_t		thread,
		    run_queue_t		run_queues);

/* Lock run queues, add thread to tail, unlock queues but don't check for preemption */
sf_return_t	(*sf_queue_add_only)(
		    meta_priority_t	priority,
		    thread_t		thread,
		    run_queue_t		run_queues);

/* Lock run queues, remove thread entry, unlock run queues */
sf_return_t	(*sf_queue_remove)(
		    thread_t		thread);

/**********
 *
 * Scheduling Policy Interfaces
 *
 **********/

/*
 * Operation list for scheduling policies.  (Modeled after the
 * device operations `.../mach_kernel/device/conf.h.')
 *
 * Key to some abbreviations:
 *     sp = scheduling policy
 *     sf = scheduling framework
 */
typedef struct sched_policy_ops {
    /* Initialize an instance of a scheduling policy */
    sf_return_t	(*sp_init)(
		sf_object_t			policy,
		int					policy_id,
		int					priority_mask_length,
		sf_priority_mask	*priority_mask);

    /* Enable/disable a scheduling policy on a processor [set] */
    sf_return_t	(*sp_enable_processor_set)(
		sf_object_t			policy,
		processor_set_t		processor_set);

    sf_return_t	(*sp_disable_processor_set)(
		sf_object_t			policy,
		processor_set_t		processor_set);

    sf_return_t	(*sp_enable_processor)(
		sf_object_t			policy,
		processor_t			processor);

    sf_return_t	(*sp_disable_processor)(
		sf_object_t			policy,
		processor_t			processor);

    /* Allow the policy to update the meta-priority of a running thread */
    sf_return_t	(*sp_thread_update_mpri)(
		sf_object_t			policy,
		sched_thread_t		thread);

    /* Notify the policy that a thread has become runnable */
    sf_return_t	(*sp_thread_unblock)(
		sf_object_t			policy,
		sched_thread_t		thread);

    /* Notify the policy that the current thread is done */
    /*** ??? Should this call take a `reason' argument? ***/
    sf_return_t	(*sp_thread_done)(
		sf_object_t			policy,
		sched_thread_t		old_thread);

    /* Notify the policy that a new thread has been selected to run */
    sf_return_t	(*sp_thread_begin)(
		sf_object_t			policy,
		sched_thread_t		new_thread);

    /* Notify the policy that an old thread is ready to be requeued */
    sf_return_t	(*sp_thread_dispatch)(
		sf_object_t			policy,
		sched_thread_t		old_thread);

    /* Attach/detach a thread from the scheduling policy */
    sf_return_t	(*sp_thread_attach)(
		sf_object_t			policy,
		sched_thread_t		thread);

    sf_return_t	(*sp_thread_detach)(
		sf_object_t			policy,
		sched_thread_t		thread);

    /* Set the thread's processor [set] */
    sf_return_t	(*sp_thread_processor)(
		sf_object_t			policy,
		sched_thread_t		*thread,
		processor_t			processor);

    sf_return_t	(*sp_thread_processor_set)(
		sf_object_t			policy,
		sched_thread_t		thread,
		processor_set_t		processor_set);

    /* Set/get a thread's scheduling attributes */
    sf_return_t	(*sp_thread_set)(
		sf_object_t			policy,
		sched_thread_t		thread,
		sp_attributes_t		policy_attributes);

    sf_return_t	(*sp_thread_get)(
		sf_object_t				policy,
		sched_thread_t			thread,
		sp_attributes_t			policy_attributes,
		sp_attributes_size_t	size);

    /* Print scheduling info for a given thread */
    int	(*sp_db_print_sched_stats)(
		sf_object_t			policy,
		sched_thread_t		thread);

    /***
     *** ??? Hopefully, many of the following operations are only
     *** temporary.  Consequently, they haven't been forced to take
     *** the same form as the others just yet.  That should happen
     *** for all of those that end up being permanent additions to the
     *** list of standard operations.
     ***/

    /* `swtch_pri()' routine -- attempt to give up processor */
    void (*sp_swtch_pri)(
		sf_object_t			policy,
		int					pri);

    /* `thread_switch()' routine -- context switch w/ optional hint */
    kern_return_t (*sp_thread_switch)(
		sf_object_t			policy,
		thread_act_t		hint_act,
		int					option,
		mach_msg_timeout_t	option_time);

    /* `thread_depress_abort()' routine -- prematurely abort depression */
    kern_return_t (*sp_thread_depress_abort)(
		sf_object_t			policy,
		sched_thread_t		thread);

    /* `thread_depress_timeout()' routine -- timeout on depression */
    void	(*sp_thread_depress_timeout)(
		sf_object_t			policy,
		thread_t			thread);

    /* `task_attach()' routine -- associate task with scheduling policy */
    sf_return_t (*sp_task_attach)(
		sf_object_t			policy,
		task_t				task);

    /* `task_detach()' routine -- disassociate task from scheduling policy */
    sf_return_t (*sp_task_detach)(
		sf_object_t			policy,
		task_t				task);

    /* `task_policy()' routine -- set scheduling policy and parameters */
    kern_return_t (*sp_task_policy)(
		sf_object_t				policy,
		task_t					task,
		policy_t				policy_id,
		policy_base_t			base,
		mach_msg_type_number_t	count,
		boolean_t				set_limit,
		boolean_t				change,
		policy_limit_t			*limit_ptr,
		int						*lc_ptr);

    /* `task_set_policy()' routine -- set scheduling policy and parameters */
    kern_return_t (*sp_task_set_policy)(
		sf_object_t				policy,
		task_t					task,
		processor_set_t			pset,
		policy_t				policy_id,
		policy_base_t			base,
		mach_msg_type_number_t	base_count,
		policy_limit_t			limit,
		mach_msg_type_number_t	limit_count,
		boolean_t				change);

    kern_return_t (*sp_task_set_sched)(
		sf_object_t				policy,
		task_t					task,
		policy_t				policy_id,
		sched_attr_t			sched_attr,
		mach_msg_type_number_t	sched_attrCnt,
		boolean_t				set_limit,
		boolean_t				change);

    kern_return_t (*sp_task_get_sched)(
		sf_object_t				policy,
		task_t					task,
		policy_t				policy_id,
		sched_attr_t			sched_attr,
		mach_msg_type_number_t	sched_attrCnt,
		mach_msg_type_number_t	sched_attr_size);

    boolean_t (*sp_thread_runnable)(
		sf_object_t			policy,
		sched_thread_t		thread);

    sf_return_t	(*sp_alarm_expired)(
		sf_object_t			policy,
		long				alarm_seqno,
		kern_return_t		result,
		int					alarm_type,
		mach_timespec_t		wakeup_time,
		void				*alarm_data);

} sp_ops_t;

/**********
 *
 * Scheduling Policy
 *
 **********/

typedef struct sf_policy {
	int					policy_id;				/* policy number */
	int					priority_mask_length;	/* length of a priority mask */
	sf_priority_mask	priority_mask;			/* mask for this policy */

	/***
	 *** ??? does this have to be so general?  why not just
	 *** have room in this struct for the priority mask?  then
	 *** there is no need for an allocation and less indirection
	 *** is required for normal access.
	 ***/

	/*
	 * This is the size of the scheduling parameters
	 * data structure for this scheduling policy, in
	 * bytes.
	 *
	 * These are the parameters that are actually
	 * communicated -- and meaningful -- outside
	 * the policy.  (This is as opposed to the
	 * internal state, which has some overlap with
	 * the scheduling parameters.  The size of the
	 * internal state is given by `sched_info_size'
	 * in this structure.)
	 *
	 * By convention, the first field in the sched
	 * parameters structure is the scheduling policy
	 * ID.  This makes the parameters more readily
	 * self-describing.
	 */
	sp_attributes_size_t	sched_attributes_size;

	/*
	 * This is the size of the scheduling policy's
	 * internal state that describes the state of a
	 * thread, in bytes.
	 */
	sp_info_size_t			sched_info_size;

	/*
	 * policy-specific versions
	 * of standard sched ops
	 */
	sp_ops_t				sp_ops;
} sched_policy_t;

#define SCHED_POLICY_NULL	((sched_policy_t *) 0)

#define policy_id_to_sched_policy(policy_id)		\
	(((policy_id) != POLICY_NULL)?					\
			&sched_policy[(policy_id)] : SCHED_POLICY_NULL)

/*
 * Declaration for array of scheduling policies known to kernel
 */
extern sched_policy_t	sched_policy[MAX_SCHED_POLS];

/*
 * Maximum sizes for scheduling-policy-specific information and 
 * attributes, calculated dynamically based on the scheduling
 * policies that were initialized at system startup time.
 */
extern	sp_info_size_t		max_sched_info_size;
extern 	sp_attributes_size_t 	max_sched_attributes_size;

#endif	/* _KERN_SF_H_ */