1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
|
/*
PsychToolbox3/Source/Common/MachPriorityMex/MachGetPriorityMex.c
PLATFORMS: OS X only.
AUTHORS:
Allen Ingling awi Allen.Ingling@nyu.edu
Mario Kleiner mk mario.kleiner@tuebingen.mpg.de
HISTORY:
8/08/02 awi wrote it.
DESCRIPTION
MachGetPriorityMex is a simplified variant of MachPriority which strips out the Psychtoolbox mex/mx abstraction layer.
For the sake of greater readability it uses a reduced argument set. See also MachSetPriorityMex.
MachGetPriorityMex(['THREAD_STANDARD_POLICY', 'THREAD_EXTENDED_POLICY','THREAD_TIME_CONSTRAINT_POLICY', 'THREAD_PRECEDENCE_POLICY'], getDefault);
The returned argument is a struct whith these fields:
priority.threadID
priority.flavor
priority.policy
priority.policySize
priority.policyFillSize
priority.getDefault
priority.isDefault
The form of the embedded struct "policy" depends on the first argument passed to MachGetPriorityMex().
THREAD_STANDARD_POLICY:
priority.flavorPolicy.no_data
THREAD_TIME_CONSTRAINT_POLICY
priority.flavorPolicy.period
priority.flavorPolicy.computation
priority.flavorPolicy.constraint
priority.flavorPolicy.preemptible
THREAD_PRECEDENCE_POLICY
priority.flavorPolicy.importance
NOTES
Arguments to thread_policy_get() are not well explained by Apple. The are documented by Apple in two places:
http://developer.apple.com/documentation/Darwin/Conceptual/KernelProgramming/scheduler/chapter_8_section_4.html
/usr/include/mach/thread_policy.h (though there is another one down /System/Library/Frameworks/)
Info from those sources is unified below.
1 INPUT (thread_act_t thread) : The thread ID. Get this by calling mach_thread_self().
2 INPUT (thread_policy_flavor_t flavor): Allowable values are THREAD_STANDARD_POLICY, THREAD_EXTENDED_POLICY, THREAD_TIME_CONSTRAINT_POLICY and THREAD_PRECEDENCE_POLICY.
Each flavor constant has an associated struct type for holding policy parameters, for example the THREAD_STANDARD_POLICY constant
matches with thread_standard_policy struct.
Apple documents THREAD_PRECEDENCE_POLICY: "Another policy call is THREAD_PRECEDENCE_POLICY. This is used for setting the relative
importance of non-real-time threads. Its calling convention is similar, except that its structure is thread_precedence_policy, and
contains only one field, an integer_t called importance, which is a signed 32-bit value." So apparently these flavors are mutually
exclusive.
How the flavor argument interacts with the get_default argument is confusing and poorly documented by Apple. flavor is an
input-onlyargument to thread_policy_get(), yet it seesm that calling thread_policy_get() with the get_default argument should tell
us what is the default policy flavor, but it can do that because the flavor argument is input only.
Here is the current theory about how to discover the current thread setting:
i. To find the current thread thread policy invoke thread_policy_get() iteratively with each of the three policy flavors and the
get_default argument unasserted. On return thread_policy_get should clear get_default for the current flavor and set get_default for
others.
ii. The contents of policy_info should be valid for the current mode. Check the count argument to verify that the ammount of data returns
matches the size of the struct which corresponds to the current flavor mode constant.
note: when invoking thread_policy_get() the info field should point to enough memory to fill the largest of the flavor's corressponding
policy_info struct types: thread_standard_policy, thread_time_constraint_policy and thread_precedence_policy.
3 INPUT (thread_policy_t policy_info): Type thread_policy_t defined (ultimately) as a pointer to type long, but the variable policy_info of that type should point to
a thread_time_constraint_policy struct allocated by the caller. thread_policy_get() fills the struct memory at the location referenced
by the input pointer. thread_policy_t looks like this:
struct thread_time_constraint_policy {
uint32_t period;
uint32_t computation;
uint32_t constraint;
boolean_t preemptible;
};
from Apple's thead_policy.h header file:
period: This is the nominal amount of time between separate
processing arrivals, specified in absolute time units. A
value of 0 indicates that there is no inherent periodicity in
the computation.
computation: This is the nominal amount of computation
time needed during a separate processing arrival, specified
in absolute time units.
constraint: This is the maximum amount of real time that
may elapse from the start of a separate processing arrival
to the end of computation for logically correct functioning,
specified in absolute time units. Must be (>= computation).
Note that latency = (constraint - computation).
preemptible: This indicates that the computation may be
interrupted, subject to the constraint specified above.
4 INPUT/OUTPUT (mach_msg_type_number_t *count): Type mach_msg_type_number_t is unsigned int. On input, "the maximum amount of storage that the calling task has allocated for the return, [on return]... overwritten by the scheduler to indicate the amount of data that was actually returned."
5 INPUT/OUTPUT (boolean_t *get_default): from Apple's thead_policy.h header file:
The extra 'get_default' parameter to the second call is
IN/OUT as follows:
1) if asserted on the way in it indicates that the default
values should be returned, not the ones currently set, in
this case 'get_default' will always be asserted on return;
2) if unasserted on the way in, the current settings are
desired and if still unasserted on return, then the info
returned reflects the current settings, otherwise if
'get_default' returns asserted, it means that there are no
current settings due to other parameters taking precedence,
and the default ones are being returned instead.
*/
#include "MachPriorityMex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
bool isError;
thread_policy_flavor_t flavorConstant;
int flavorPolicySize, flavorPolicySizeBytes, kernError;
task_t threadID;
thread_policy_t threadPolicy;
mach_msg_type_number_t policySizeFilled;
boolean_t isDefault, getDefault;
char commandString[COMMAND_STRING_LENGTH];
// for return structure
// ...outer
const char *outerNames[] = {"threadID", "flavor", "policy", "policySize", "policyFillSize", "getDefault", "isDefault"};
mwSize numOuterDims=2, numOuterFields=7;
mwSize outerDims[2]={1,1};
// ...inner
const char *standardNames[] = {"no_data"};
int numInnerFieldsStandard= 1;
/*
const char *extendedNames[] = {"timeshare"};
int numInnerFieldsExtended= 1;
*/
const char *timeConstraintNames[]= {"period", "computation", "constraint", "preemptible"};
int numInnerFieldsTimeConstraint= 4;
const char *precedenceNames[]= {"imporantance"};
int numInnerFieldsPrecedence= 1;
mwSize numInnerDims=2;
mwSize innerDims[2]={1,1};
// ...both
mxArray *tempFieldValue, *innerStruct, *outerStruct;
//get the policy flavor constant specified by the user and the getDefault argument
if(nrhs<2 || nrhs > 2)
mexErrMsgTxt("MachGetPriorityMex requires two input arguments. See help MachGetPriorityMex.");
if(!mxIsChar(prhs[0]))
mexErrMsgTxt("First input argument is not a string. See help MachGetPriorityMex.");
mxGetString(prhs[0], commandString, COMMAND_STRING_LENGTH);
isError=GetFlavorConstantFromFlavorString(commandString, mxGetM(prhs[0]) * mxGetN(prhs[0]), &flavorConstant); //case sensitive.
if(isError)
mexErrMsgTxt("Unrecognized command. See help MachGetPriorityMex.");
if(!(mxIsDouble(prhs[1]) || mxIsLogical(prhs[1])) || mxGetN(prhs[1]) * mxGetM(prhs[1]) != 1)
mexErrMsgTxt("Second argument must be 1x1 logical or double value. See help MachGetPriorityMex.");
if(mxIsLogical(prhs[1]))
getDefault= (boolean_t)mxGetLogicals(prhs[1])[0];
if(mxIsDouble(prhs[1]))
getDefault= (boolean_t)mxGetPr(prhs[1])[0];
//read the priority settings
switch(flavorConstant){
case THREAD_STANDARD_POLICY:
flavorPolicySizeBytes=sizeof(thread_standard_policy_data_t);
flavorPolicySize=THREAD_STANDARD_POLICY_COUNT;
break;
case THREAD_TIME_CONSTRAINT_POLICY:
flavorPolicySizeBytes=sizeof(thread_time_constraint_policy_data_t);
flavorPolicySize=THREAD_TIME_CONSTRAINT_POLICY_COUNT;
break;
case THREAD_PRECEDENCE_POLICY:
flavorPolicySizeBytes=sizeof(thread_precedence_policy_data_t);
flavorPolicySize=THREAD_PRECEDENCE_POLICY_COUNT;
break;
}
threadPolicy=(thread_policy_t)malloc(flavorPolicySizeBytes);
threadID= mach_thread_self();
policySizeFilled=flavorPolicySize;
isDefault=getDefault;
kernError=thread_policy_get(threadID, flavorConstant, threadPolicy, &policySizeFilled, &isDefault);
//create and populate the return structure
outerStruct= mxCreateStructArray(numOuterDims, outerDims, numOuterFields, outerNames);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]=(double)threadID;
mxSetField(outerStruct, 0, "threadID", tempFieldValue);
tempFieldValue= mxCreateString(commandString);
mxSetField(outerStruct, 0, "flavor", tempFieldValue);
switch(flavorConstant){
case THREAD_STANDARD_POLICY:
innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsStandard, standardNames);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]= (double)((thread_standard_policy_t)threadPolicy)->no_data;
mxSetField(innerStruct, 0, "no_data", tempFieldValue);
break;
/* THREAD_EXTENDED_POLICY is equal to THREAD_STANDARD_POLICY. Also, THREAD_EXTENDED_POLICY is undocumented. So we ignore it.
case THREAD_EXTENDED_POLICY:
innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsExtended, extendedNames);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]= (double)((thread_extended_policy_t)threadPolicy)->timeshare;
mxSetField(innerStruct, 1, "timeshare", tempFieldValue);
break;
*/
case THREAD_TIME_CONSTRAINT_POLICY:
innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsTimeConstraint, timeConstraintNames);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->period;
mxSetField(innerStruct, 0, "period", tempFieldValue);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->computation;
mxSetField(innerStruct, 0, "computation", tempFieldValue);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->constraint;
mxSetField(innerStruct, 0, "constraint", tempFieldValue);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->preemptible;
mxSetField(innerStruct, 0, "preemptible", tempFieldValue);
break;
case THREAD_PRECEDENCE_POLICY:
innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsPrecedence, precedenceNames);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]= (double)((thread_precedence_policy_t)threadPolicy)->importance;
mxSetField(innerStruct, 0, "imporantance", tempFieldValue);
break;
}
mxSetField(outerStruct,0, "policy", innerStruct);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]=flavorPolicySize;
mxSetField(outerStruct, 0, "policySize", tempFieldValue);
tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL);
mxGetPr(tempFieldValue)[0]=policySizeFilled;
mxSetField(outerStruct, 0, "policyFillSize", tempFieldValue);
tempFieldValue= mxCreateLogicalMatrix(1, 1);
mxGetLogicals(tempFieldValue)[0]=(bool)getDefault;
mxSetField(outerStruct, 0, "getDefault", tempFieldValue);
tempFieldValue= mxCreateLogicalMatrix(1, 1);
mxGetLogicals(tempFieldValue)[0]=(bool)isDefault;
mxSetField(outerStruct, 0, "isDefault", tempFieldValue);
plhs[0]=outerStruct;
free((void*)threadPolicy);
}
|