File: MachGetPriorityMex.c

package info (click to toggle)
psychtoolbox-3 3.0.19.14.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,796 kB
  • sloc: ansic: 176,245; cpp: 20,103; objc: 5,393; sh: 2,753; python: 1,397; php: 384; makefile: 193; java: 113
file content (278 lines) | stat: -rw-r--r-- 16,766 bytes parent folder | download | duplicates (6)
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);        
}