1 /******************************************************************************
3 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
6 *****************************************************************************/
9 * Copyright (C) 2000, 2001 R. Byron Moore
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #define _COMPONENT ACPI_DISPATCHER
30 MODULE_NAME ("dsmethod")
33 /*******************************************************************************
35 * FUNCTION: Acpi_ds_parse_method
37 * PARAMETERS: Obj_handle - Node of the method
38 * Level - Current nesting level
39 * Context - Points to a method counter
40 * Return_value - Not used
44 * DESCRIPTION: Call the parser and parse the AML that is
45 * associated with the method.
47 * MUTEX: Assumes parser is locked
49 ******************************************************************************/
52 acpi_ds_parse_method (
53 ACPI_HANDLE obj_handle
)
56 ACPI_OPERAND_OBJECT
*obj_desc
;
57 ACPI_PARSE_OBJECT
*op
;
58 ACPI_NAMESPACE_NODE
*node
;
59 ACPI_OWNER_ID owner_id
;
62 /* Parameter Validation */
65 return (AE_NULL_ENTRY
);
69 /* Extract the method object from the method Node */
71 node
= (ACPI_NAMESPACE_NODE
*) obj_handle
;
72 obj_desc
= node
->object
;
74 return (AE_NULL_OBJECT
);
77 /* Create a mutex for the method if there is a concurrency limit */
79 if ((obj_desc
->method
.concurrency
!= INFINITE_CONCURRENCY
) &&
80 (!obj_desc
->method
.semaphore
)) {
81 status
= acpi_os_create_semaphore (obj_desc
->method
.concurrency
,
82 obj_desc
->method
.concurrency
,
83 &obj_desc
->method
.semaphore
);
84 if (ACPI_FAILURE (status
)) {
90 * Allocate a new parser op to be the root of the parsed
93 op
= acpi_ps_alloc_op (AML_METHOD_OP
);
95 return (AE_NO_MEMORY
);
98 /* Init new op with the method name and pointer back to the Node */
100 acpi_ps_set_name (op
, node
->name
);
105 * Parse the method, first pass
107 * The first pass load is
108 * where newly declared named objects are
109 * added into the namespace. Actual evaluation of
110 * the named objects (what would be called a "second
111 * pass") happens during the actual execution of the
112 * method so that operands to the named objects can
113 * take on dynamic run-time values.
115 status
= acpi_ps_parse_aml (op
, obj_desc
->method
.pcode
,
116 obj_desc
->method
.pcode_length
,
117 ACPI_PARSE_LOAD_PASS1
| ACPI_PARSE_DELETE_TREE
,
119 acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
121 if (ACPI_FAILURE (status
)) {
125 /* Get a new Owner_id for objects created by this method */
127 owner_id
= acpi_cm_allocate_owner_id (OWNER_TYPE_METHOD
);
128 obj_desc
->method
.owning_id
= owner_id
;
130 /* Install the parsed tree in the method object */
131 /* TBD: [Restructure] Obsolete field? */
133 acpi_ps_delete_parse_tree (op
);
140 /*******************************************************************************
142 * FUNCTION: Acpi_ds_begin_method_execution
144 * PARAMETERS: Method_node - Node of the method
145 * Obj_desc - The method object
146 * Calling_method_node - Caller of this method (if non-null)
150 * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
151 * increments the thread count, and waits at the method semaphore
152 * for clearance to execute.
154 * MUTEX: Locks/unlocks parser.
156 ******************************************************************************/
159 acpi_ds_begin_method_execution (
160 ACPI_NAMESPACE_NODE
*method_node
,
161 ACPI_OPERAND_OBJECT
*obj_desc
,
162 ACPI_NAMESPACE_NODE
*calling_method_node
)
164 ACPI_STATUS status
= AE_OK
;
168 return (AE_NULL_ENTRY
);
173 * If there is a concurrency limit on this method, we need to
174 * obtain a unit from the method semaphore.
176 if (obj_desc
->method
.semaphore
) {
178 * Allow recursive method calls, up to the reentrancy/concurrency
179 * limit imposed by the SERIALIZED rule and the Sync_level method
182 * The point of this code is to avoid permanently blocking a
183 * thread that is making recursive method calls.
185 if (method_node
== calling_method_node
) {
186 if (obj_desc
->method
.thread_count
>= obj_desc
->method
.concurrency
) {
187 return (AE_AML_METHOD_LIMIT
);
192 * Get a unit from the method semaphore. This releases the
193 * interpreter if we block
195 status
= acpi_aml_system_wait_semaphore (obj_desc
->method
.semaphore
,
201 * Increment the method parse tree thread count since it has been
202 * reentered one more time (even if it is the same thread)
204 obj_desc
->method
.thread_count
++;
210 /*******************************************************************************
212 * FUNCTION: Acpi_ds_call_control_method
214 * PARAMETERS: Walk_state - Current state of the walk
215 * Op - Current Op to be walked
219 * DESCRIPTION: Transfer execution to a called control method
221 ******************************************************************************/
224 acpi_ds_call_control_method (
225 ACPI_WALK_LIST
*walk_list
,
226 ACPI_WALK_STATE
*this_walk_state
,
227 ACPI_PARSE_OBJECT
*op
)
230 ACPI_NAMESPACE_NODE
*method_node
;
231 ACPI_OPERAND_OBJECT
*obj_desc
;
232 ACPI_WALK_STATE
*next_walk_state
;
233 ACPI_PARSE_STATE
*parser_state
;
238 * Get the namespace entry for the control method we are about to call
240 method_node
= this_walk_state
->method_call_node
;
242 return (AE_NULL_ENTRY
);
245 obj_desc
= acpi_ns_get_attached_object (method_node
);
247 return (AE_NULL_OBJECT
);
251 /* Init for new method, wait on concurrency semaphore */
253 status
= acpi_ds_begin_method_execution (method_node
, obj_desc
,
254 this_walk_state
->method_node
);
255 if (ACPI_FAILURE (status
)) {
259 /* Create and initialize a new parser state */
261 parser_state
= acpi_ps_create_state (obj_desc
->method
.pcode
,
262 obj_desc
->method
.pcode_length
);
264 return (AE_NO_MEMORY
);
267 acpi_ps_init_scope (parser_state
, NULL
);
268 parser_state
->start_node
= method_node
;
271 /* Create a new state for the preempting walk */
273 next_walk_state
= acpi_ds_create_walk_state (obj_desc
->method
.owning_id
,
274 NULL
, obj_desc
, walk_list
);
275 if (!next_walk_state
) {
276 /* TBD: delete parser state */
278 return (AE_NO_MEMORY
);
281 next_walk_state
->walk_type
= WALK_METHOD
;
282 next_walk_state
->method_node
= method_node
;
283 next_walk_state
->parser_state
= parser_state
;
284 next_walk_state
->parse_flags
= this_walk_state
->parse_flags
;
285 next_walk_state
->descending_callback
= this_walk_state
->descending_callback
;
286 next_walk_state
->ascending_callback
= this_walk_state
->ascending_callback
;
288 /* The Next_op of the Next_walk will be the beginning of the method */
289 /* TBD: [Restructure] -- obsolete? */
291 next_walk_state
->next_op
= NULL
;
293 /* Open a new scope */
295 status
= acpi_ds_scope_stack_push (method_node
,
296 ACPI_TYPE_METHOD
, next_walk_state
);
297 if (ACPI_FAILURE (status
)) {
303 * Initialize the arguments for the method. The resolved
304 * arguments were put on the previous walk state's operand
305 * stack. Operands on the previous walk state stack always
308 status
= acpi_ds_method_data_init_args (&this_walk_state
->operands
[0],
309 this_walk_state
->num_operands
,
311 if (ACPI_FAILURE (status
)) {
316 /* Create and init a Root Node */
318 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
320 return (AE_NO_MEMORY
);
323 status
= acpi_ps_parse_aml (op
, obj_desc
->method
.pcode
,
324 obj_desc
->method
.pcode_length
,
325 ACPI_PARSE_LOAD_PASS1
| ACPI_PARSE_DELETE_TREE
,
326 method_node
, NULL
, NULL
,
327 acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
328 acpi_ps_delete_parse_tree (op
);
332 * Delete the operands on the previous walkstate operand stack
333 * (they were copied to new objects)
335 for (i
= 0; i
< obj_desc
->method
.param_count
; i
++) {
336 acpi_cm_remove_reference (this_walk_state
->operands
[i
]);
337 this_walk_state
->operands
[i
] = NULL
;
340 /* Clear the operand stack */
342 this_walk_state
->num_operands
= 0;
348 /* On error, we must delete the new walk state */
351 acpi_ds_terminate_control_method (next_walk_state
);
352 acpi_ds_delete_walk_state (next_walk_state
);
358 /*******************************************************************************
360 * FUNCTION: Acpi_ds_restart_control_method
362 * PARAMETERS: Walk_state - State of the method when it was preempted
363 * Op - Pointer to new current op
367 * DESCRIPTION: Restart a method that was preempted
369 ******************************************************************************/
372 acpi_ds_restart_control_method (
373 ACPI_WALK_STATE
*walk_state
,
374 ACPI_OPERAND_OBJECT
*return_desc
)
380 if (walk_state
->return_used
) {
382 * Get the return value (if any) from the previous method.
383 * NULL if no return value
385 status
= acpi_ds_result_push (return_desc
, walk_state
);
386 if (ACPI_FAILURE (status
)) {
387 acpi_cm_remove_reference (return_desc
);
394 * Delete the return value if it will not be used by the
397 acpi_cm_remove_reference (return_desc
);
407 /*******************************************************************************
409 * FUNCTION: Acpi_ds_terminate_control_method
411 * PARAMETERS: Walk_state - State of the method
415 * DESCRIPTION: Terminate a control method. Delete everything that the method
416 * created, delete all locals and arguments, and delete the parse
419 ******************************************************************************/
422 acpi_ds_terminate_control_method (
423 ACPI_WALK_STATE
*walk_state
)
426 ACPI_OPERAND_OBJECT
*obj_desc
;
427 ACPI_NAMESPACE_NODE
*method_node
;
430 /* The method object should be stored in the walk state */
432 obj_desc
= walk_state
->method_desc
;
437 /* Delete all arguments and locals */
439 acpi_ds_method_data_delete_all (walk_state
);
442 * Lock the parser while we terminate this method.
443 * If this is the last thread executing the method,
444 * we have additional cleanup to perform
446 acpi_cm_acquire_mutex (ACPI_MTX_PARSER
);
449 /* Signal completion of the execution of this method if necessary */
451 if (walk_state
->method_desc
->method
.semaphore
) {
452 status
= acpi_os_signal_semaphore (
453 walk_state
->method_desc
->method
.semaphore
, 1);
456 /* Decrement the thread count on the method parse tree */
458 walk_state
->method_desc
->method
.thread_count
--;
459 if (!walk_state
->method_desc
->method
.thread_count
) {
461 * There are no more threads executing this method. Perform
462 * additional cleanup.
464 * The method Node is stored in the walk state
466 method_node
= walk_state
->method_node
;
469 * Delete any namespace entries created immediately underneath
472 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
473 if (method_node
->child
) {
474 acpi_ns_delete_namespace_subtree (method_node
);
478 * Delete any namespace entries created anywhere else within
481 acpi_ns_delete_namespace_by_owner (walk_state
->method_desc
->method
.owning_id
);
482 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
485 acpi_cm_release_mutex (ACPI_MTX_PARSER
);