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
37 #define _COMPONENT ACPI_DISPATCHER
38 MODULE_NAME ("dsmethod")
41 /*******************************************************************************
43 * FUNCTION: Acpi_ds_parse_method
45 * PARAMETERS: Obj_handle - Node of the method
46 * Level - Current nesting level
47 * Context - Points to a method counter
48 * Return_value - Not used
52 * DESCRIPTION: Call the parser and parse the AML that is
53 * associated with the method.
55 * MUTEX: Assumes parser is locked
57 ******************************************************************************/
60 acpi_ds_parse_method (
61 ACPI_HANDLE obj_handle
)
64 ACPI_OPERAND_OBJECT
*obj_desc
;
65 ACPI_PARSE_OBJECT
*op
;
66 ACPI_NAMESPACE_NODE
*node
;
67 ACPI_OWNER_ID owner_id
;
70 /* Parameter Validation */
73 return (AE_NULL_ENTRY
);
77 /* Extract the method object from the method Node */
79 node
= (ACPI_NAMESPACE_NODE
*) obj_handle
;
80 obj_desc
= node
->object
;
82 return (AE_NULL_OBJECT
);
85 /* Create a mutex for the method if there is a concurrency limit */
87 if ((obj_desc
->method
.concurrency
!= INFINITE_CONCURRENCY
) &&
88 (!obj_desc
->method
.semaphore
)) {
89 status
= acpi_os_create_semaphore (obj_desc
->method
.concurrency
,
90 obj_desc
->method
.concurrency
,
91 &obj_desc
->method
.semaphore
);
92 if (ACPI_FAILURE (status
)) {
98 * Allocate a new parser op to be the root of the parsed
101 op
= acpi_ps_alloc_op (AML_METHOD_OP
);
103 return (AE_NO_MEMORY
);
106 /* Init new op with the method name and pointer back to the Node */
108 acpi_ps_set_name (op
, node
->name
);
113 * Parse the method, first pass
115 * The first pass load is
116 * where newly declared named objects are
117 * added into the namespace. Actual evaluation of
118 * the named objects (what would be called a "second
119 * pass") happens during the actual execution of the
120 * method so that operands to the named objects can
121 * take on dynamic run-time values.
123 status
= acpi_ps_parse_aml (op
, obj_desc
->method
.pcode
,
124 obj_desc
->method
.pcode_length
,
125 ACPI_PARSE_LOAD_PASS1
| ACPI_PARSE_DELETE_TREE
,
127 acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
129 if (ACPI_FAILURE (status
)) {
133 /* Get a new Owner_id for objects created by this method */
135 owner_id
= acpi_cm_allocate_owner_id (OWNER_TYPE_METHOD
);
136 obj_desc
->method
.owning_id
= owner_id
;
138 /* Install the parsed tree in the method object */
139 /* TBD: [Restructure] Obsolete field? */
141 acpi_ps_delete_parse_tree (op
);
148 /*******************************************************************************
150 * FUNCTION: Acpi_ds_begin_method_execution
152 * PARAMETERS: Method_node - Node of the method
153 * Obj_desc - The method object
154 * Calling_method_node - Caller of this method (if non-null)
158 * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
159 * increments the thread count, and waits at the method semaphore
160 * for clearance to execute.
162 * MUTEX: Locks/unlocks parser.
164 ******************************************************************************/
167 acpi_ds_begin_method_execution (
168 ACPI_NAMESPACE_NODE
*method_node
,
169 ACPI_OPERAND_OBJECT
*obj_desc
,
170 ACPI_NAMESPACE_NODE
*calling_method_node
)
172 ACPI_STATUS status
= AE_OK
;
176 return (AE_NULL_ENTRY
);
181 * If there is a concurrency limit on this method, we need to
182 * obtain a unit from the method semaphore.
184 if (obj_desc
->method
.semaphore
) {
186 * Allow recursive method calls, up to the reentrancy/concurrency
187 * limit imposed by the SERIALIZED rule and the Sync_level method
190 * The point of this code is to avoid permanently blocking a
191 * thread that is making recursive method calls.
193 if (method_node
== calling_method_node
) {
194 if (obj_desc
->method
.thread_count
>= obj_desc
->method
.concurrency
) {
195 return (AE_AML_METHOD_LIMIT
);
200 * Get a unit from the method semaphore. This releases the
201 * interpreter if we block
203 status
= acpi_aml_system_wait_semaphore (obj_desc
->method
.semaphore
,
209 * Increment the method parse tree thread count since it has been
210 * reentered one more time (even if it is the same thread)
212 obj_desc
->method
.thread_count
++;
218 /*******************************************************************************
220 * FUNCTION: Acpi_ds_call_control_method
222 * PARAMETERS: Walk_state - Current state of the walk
223 * Op - Current Op to be walked
227 * DESCRIPTION: Transfer execution to a called control method
229 ******************************************************************************/
232 acpi_ds_call_control_method (
233 ACPI_WALK_LIST
*walk_list
,
234 ACPI_WALK_STATE
*this_walk_state
,
235 ACPI_PARSE_OBJECT
*op
)
238 ACPI_NAMESPACE_NODE
*method_node
;
239 ACPI_OPERAND_OBJECT
*obj_desc
;
240 ACPI_WALK_STATE
*next_walk_state
;
241 ACPI_PARSE_STATE
*parser_state
;
246 * Get the namespace entry for the control method we are about to call
248 method_node
= this_walk_state
->method_call_node
;
250 return (AE_NULL_ENTRY
);
253 obj_desc
= acpi_ns_get_attached_object (method_node
);
255 return (AE_NULL_OBJECT
);
259 /* Init for new method, wait on concurrency semaphore */
261 status
= acpi_ds_begin_method_execution (method_node
, obj_desc
,
262 this_walk_state
->method_node
);
263 if (ACPI_FAILURE (status
)) {
267 /* Create and initialize a new parser state */
269 parser_state
= acpi_ps_create_state (obj_desc
->method
.pcode
,
270 obj_desc
->method
.pcode_length
);
272 return (AE_NO_MEMORY
);
275 acpi_ps_init_scope (parser_state
, NULL
);
276 parser_state
->start_node
= method_node
;
279 /* Create a new state for the preempting walk */
281 next_walk_state
= acpi_ds_create_walk_state (obj_desc
->method
.owning_id
,
282 NULL
, obj_desc
, walk_list
);
283 if (!next_walk_state
) {
284 /* TBD: delete parser state */
286 return (AE_NO_MEMORY
);
289 next_walk_state
->walk_type
= WALK_METHOD
;
290 next_walk_state
->method_node
= method_node
;
291 next_walk_state
->parser_state
= parser_state
;
292 next_walk_state
->parse_flags
= this_walk_state
->parse_flags
;
293 next_walk_state
->descending_callback
= this_walk_state
->descending_callback
;
294 next_walk_state
->ascending_callback
= this_walk_state
->ascending_callback
;
296 /* The Next_op of the Next_walk will be the beginning of the method */
297 /* TBD: [Restructure] -- obsolete? */
299 next_walk_state
->next_op
= NULL
;
301 /* Open a new scope */
303 status
= acpi_ds_scope_stack_push (method_node
,
304 ACPI_TYPE_METHOD
, next_walk_state
);
305 if (ACPI_FAILURE (status
)) {
311 * Initialize the arguments for the method. The resolved
312 * arguments were put on the previous walk state's operand
313 * stack. Operands on the previous walk state stack always
316 status
= acpi_ds_method_data_init_args (&this_walk_state
->operands
[0],
317 this_walk_state
->num_operands
,
319 if (ACPI_FAILURE (status
)) {
324 /* Create and init a Root Node */
326 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
328 return (AE_NO_MEMORY
);
331 status
= acpi_ps_parse_aml (op
, obj_desc
->method
.pcode
,
332 obj_desc
->method
.pcode_length
,
333 ACPI_PARSE_LOAD_PASS1
| ACPI_PARSE_DELETE_TREE
,
334 method_node
, NULL
, NULL
,
335 acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
336 acpi_ps_delete_parse_tree (op
);
340 * Delete the operands on the previous walkstate operand stack
341 * (they were copied to new objects)
343 for (i
= 0; i
< obj_desc
->method
.param_count
; i
++) {
344 acpi_cm_remove_reference (this_walk_state
->operands
[i
]);
345 this_walk_state
->operands
[i
] = NULL
;
348 /* Clear the operand stack */
350 this_walk_state
->num_operands
= 0;
356 /* On error, we must delete the new walk state */
359 acpi_ds_terminate_control_method (next_walk_state
);
360 acpi_ds_delete_walk_state (next_walk_state
);
366 /*******************************************************************************
368 * FUNCTION: Acpi_ds_restart_control_method
370 * PARAMETERS: Walk_state - State of the method when it was preempted
371 * Op - Pointer to new current op
375 * DESCRIPTION: Restart a method that was preempted
377 ******************************************************************************/
380 acpi_ds_restart_control_method (
381 ACPI_WALK_STATE
*walk_state
,
382 ACPI_OPERAND_OBJECT
*return_desc
)
388 if (walk_state
->return_used
) {
390 * Get the return value (if any) from the previous method.
391 * NULL if no return value
393 status
= acpi_ds_result_push (return_desc
, walk_state
);
394 if (ACPI_FAILURE (status
)) {
395 acpi_cm_remove_reference (return_desc
);
402 * Delete the return value if it will not be used by the
405 acpi_cm_remove_reference (return_desc
);
415 /*******************************************************************************
417 * FUNCTION: Acpi_ds_terminate_control_method
419 * PARAMETERS: Walk_state - State of the method
423 * DESCRIPTION: Terminate a control method. Delete everything that the method
424 * created, delete all locals and arguments, and delete the parse
427 ******************************************************************************/
430 acpi_ds_terminate_control_method (
431 ACPI_WALK_STATE
*walk_state
)
434 ACPI_OPERAND_OBJECT
*obj_desc
;
435 ACPI_NAMESPACE_NODE
*method_node
;
438 /* The method object should be stored in the walk state */
440 obj_desc
= walk_state
->method_desc
;
445 /* Delete all arguments and locals */
447 acpi_ds_method_data_delete_all (walk_state
);
450 * Lock the parser while we terminate this method.
451 * If this is the last thread executing the method,
452 * we have additional cleanup to perform
454 acpi_cm_acquire_mutex (ACPI_MTX_PARSER
);
457 /* Signal completion of the execution of this method if necessary */
459 if (walk_state
->method_desc
->method
.semaphore
) {
460 status
= acpi_os_signal_semaphore (
461 walk_state
->method_desc
->method
.semaphore
, 1);
464 /* Decrement the thread count on the method parse tree */
466 walk_state
->method_desc
->method
.thread_count
--;
467 if (!walk_state
->method_desc
->method
.thread_count
) {
469 * There are no more threads executing this method. Perform
470 * additional cleanup.
472 * The method Node is stored in the walk state
474 method_node
= walk_state
->method_node
;
477 * Delete any namespace entries created immediately underneath
480 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
481 if (method_node
->child
) {
482 acpi_ns_delete_namespace_subtree (method_node
);
486 * Delete any namespace entries created anywhere else within
489 acpi_ns_delete_namespace_by_owner (walk_state
->method_desc
->method
.owning_id
);
490 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
493 acpi_cm_release_mutex (ACPI_MTX_PARSER
);