2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <atm/atm_internal.h>
30 #include <mach/mach_types.h>
31 #include <mach/kern_return.h>
32 #include <ipc/ipc_port.h>
33 #include <mach/mach_vm.h>
34 #include <mach/vm_map.h>
35 #include <vm/vm_map.h>
36 #include <atm/atm_notification.h>
37 #include <mach/host_priv.h>
38 #include <mach/host_special_ports.h>
39 #include <kern/host.h>
40 #include <kern/kalloc.h>
42 #define MAX_ATM_VALUES (2 * 4096)
43 #define MAX_TRACE_BUFFER_SIZE (0x40000000) /* Restrict to 1GB per task */
44 #define MAX_MAILBOX_SIZE (8 * 4096)
46 #define ATM_VALUE_TO_HANDLE(x) (CAST_DOWN(atm_voucher_id_t, (x)))
47 #define HANDLE_TO_ATM_VALUE(x) (CAST_DOWN(atm_value_t, (x)))
49 #define ATM_MAX_HASH_TABLE_SIZE (256)
50 #define AID_HASH_MASK (0xFF)
51 #define AID_TO_HASH(x) ((x) & (AID_HASH_MASK))
53 #define ATM_LIST_DEAD_MAX 15
55 #define AID_ARRAY_COUNT_MAX (256)
57 struct atm_value_hash atm_value_hash_table
[ATM_MAX_HASH_TABLE_SIZE
];
60 /* Global flag to disable ATM. ATM get value and memory registration will return error. */
61 boolean_t disable_atm
= FALSE
;
63 #if DEVELOPMENT || DEBUG
64 queue_head_t atm_descriptors_list
;
65 queue_head_t atm_values_list
;
68 ipc_voucher_attr_control_t voucher_attr_control
; /* communication channel from ATM to voucher system */
69 static zone_t atm_value_zone
, atm_descriptors_zone
, atm_link_objects_zone
;
71 static aid_t
get_aid();
72 static atm_value_t
atm_value_alloc_init();
73 static void atm_value_dealloc(atm_value_t atm_value
);
74 static void atm_hash_table_init();
75 static void atm_value_hash_table_insert(atm_value_t new_atm_value
);
76 static void atm_value_hash_table_delete(atm_value_t atm_value
);
77 static atm_value_t
get_atm_value_from_aid(aid_t aid
);
78 static void atm_value_get_ref(atm_value_t atm_value
);
79 static kern_return_t
atm_listener_insert(atm_value_t atm_value
, atm_task_descriptor_t task_descriptor
, mailbox_offset_t mailbox_offset
);
80 static void atm_listener_delete_all(atm_value_t atm_value
);
81 static atm_task_descriptor_t
atm_task_descriptor_alloc_init(mach_port_t trace_buffer
,uint64_t buffer_size
, void *mailbox_addr
, uint64_t mailbox_array_size
, __assert_only task_t task
);
82 static void atm_descriptor_get_reference(atm_task_descriptor_t task_descriptor
);
83 static void atm_task_descriptor_dealloc(atm_task_descriptor_t task_descriptor
);
84 static mach_atm_subaid_t
atm_get_min_sub_aid(atm_value_t atm_value
);
86 atm_get_min_sub_aid_array(aid_t
*aid_array
, mach_atm_subaid_t
*subaid_array
, uint32_t count
) __unused
;
87 static kern_return_t
atm_value_unregister(atm_value_t atm_value
, atm_task_descriptor_t task_descriptor
, mailbox_offset_t mailbox_offset
);
88 static kern_return_t
atm_listener_delete(atm_value_t atm_value
, atm_task_descriptor_t task_descriptor
, mailbox_offset_t mailbox_offset
);
89 static void atm_link_get_reference(atm_link_object_t link_object
);
90 static void atm_link_dealloc(atm_link_object_t link_object
);
91 kern_return_t
atm_invoke_collection(atm_value_t atm_value
, uint64_t sub_activity_id
, uint32_t flags
);
92 kern_return_t
atm_send_user_notification(aid_t aid
, uint64_t subaid
, mach_port_t
*buffers_array
, uint64_t *sizes_array
, mach_msg_type_number_t count
, uint32_t flags
);
96 ipc_voucher_attr_manager_t __assert_only manager
,
97 mach_voucher_attr_key_t __assert_only key
,
98 mach_voucher_attr_value_handle_t value
,
99 mach_voucher_attr_value_reference_t sync
);
103 ipc_voucher_attr_manager_t __assert_only manager
,
104 mach_voucher_attr_key_t __assert_only key
,
105 mach_voucher_attr_recipe_command_t command
,
106 mach_voucher_attr_value_handle_array_t prev_values
,
107 mach_msg_type_number_t __assert_only prev_value_count
,
108 mach_voucher_attr_content_t recipe
,
109 mach_voucher_attr_content_size_t recipe_size
,
110 mach_voucher_attr_value_handle_t
*out_value
,
111 ipc_voucher_t
*out_value_voucher
);
115 ipc_voucher_attr_manager_t __assert_only manager
,
116 mach_voucher_attr_key_t __assert_only key
,
117 mach_voucher_attr_value_handle_array_t values
,
118 mach_msg_type_number_t value_count
,
119 mach_voucher_attr_recipe_command_t
*out_command
,
120 mach_voucher_attr_content_t out_recipe
,
121 mach_voucher_attr_content_size_t
*in_out_recipe_size
);
125 ipc_voucher_attr_manager_t __assert_only manager
,
126 mach_voucher_attr_key_t __assert_only key
,
127 mach_voucher_attr_value_handle_array_t values
,
128 mach_msg_type_number_t value_count
,
129 mach_voucher_attr_command_t command
,
130 mach_voucher_attr_content_t in_content
,
131 mach_voucher_attr_content_size_t in_content_size
,
132 mach_voucher_attr_content_t out_content
,
133 mach_voucher_attr_content_size_t
*in_out_content_size
);
136 atm_release(ipc_voucher_attr_manager_t __assert_only manager
);
139 * communication channel from voucher system to ATM
141 struct ipc_voucher_attr_manager atm_manager
= {
142 .ivam_release_value
= atm_release_value
,
143 .ivam_get_value
= atm_get_value
,
144 .ivam_extract_content
= atm_extract_content
,
145 .ivam_command
= atm_command
,
146 .ivam_release
= atm_release
,
149 #if DEVELOPMENT || DEBUG
150 decl_lck_mtx_data(, atm_descriptors_list_lock
);
151 decl_lck_mtx_data(, atm_values_list_lock
);
153 lck_grp_t atm_dev_lock_grp
;
154 lck_attr_t atm_dev_lock_attr
;
155 lck_grp_attr_t atm_dev_lock_grp_attr
;
158 extern vm_map_t kernel_map
;
160 * Global aid. Incremented on each get_aid.
165 * Lock group attributes for atm sub system.
167 lck_grp_t atm_lock_grp
;
168 lck_attr_t atm_lock_attr
;
169 lck_grp_attr_t atm_lock_grp_attr
;
174 * Purpose: Initialize the atm subsystem.
180 kern_return_t kr
= KERN_SUCCESS
;
183 /* Disable atm if disable_atm present in device-tree properties or in boot-args */
184 if ((PE_get_default("kern.disable_atm", temp_buf
, sizeof(temp_buf
))) ||
185 (PE_parse_boot_argn("-disable_atm", temp_buf
, sizeof(temp_buf
)))) {
189 /* setup zones for descriptors, values and link objects */
190 atm_value_zone
= zinit(sizeof(struct atm_value
),
191 MAX_ATM_VALUES
* sizeof(struct atm_value
),
192 sizeof(struct atm_value
),
195 atm_descriptors_zone
= zinit(sizeof(struct atm_task_descriptor
),
196 MAX_ATM_VALUES
* sizeof(struct atm_task_descriptor
),
197 sizeof(struct atm_task_descriptor
),
198 "atm_task_descriptors");
200 atm_link_objects_zone
= zinit(sizeof(struct atm_link_object
),
201 MAX_ATM_VALUES
* sizeof(struct atm_link_object
),
202 sizeof(struct atm_link_object
),
205 /* Initialize atm lock group and lock attributes. */
206 lck_grp_attr_setdefault(&atm_lock_grp_attr
);
207 lck_grp_init(&atm_lock_grp
, "atm_lock", &atm_lock_grp_attr
);
208 lck_attr_setdefault(&atm_lock_attr
);
211 atm_hash_table_init();
213 #if DEVELOPMENT || DEBUG
214 /* Initialize global atm development lock group and lock attributes. */
215 lck_grp_attr_setdefault(&atm_dev_lock_grp_attr
);
216 lck_grp_init(&atm_dev_lock_grp
, "atm_dev_lock", &atm_dev_lock_grp_attr
);
217 lck_attr_setdefault(&atm_dev_lock_attr
);
219 lck_mtx_init(&atm_descriptors_list_lock
, &atm_dev_lock_grp
, &atm_dev_lock_attr
);
220 lck_mtx_init(&atm_values_list_lock
, &atm_dev_lock_grp
, &atm_dev_lock_attr
);
222 queue_init(&atm_descriptors_list
);
223 queue_init(&atm_values_list
);
226 /* Register the atm manager with the Vouchers sub system. */
227 kr
= ipc_register_well_known_mach_voucher_attr_manager(
230 MACH_VOUCHER_ATTR_KEY_ATM
,
231 &voucher_attr_control
);
232 if (kr
!= KERN_SUCCESS
)
233 panic("ATM subsystem initialization failed");
235 kprintf("ATM subsystem is initialized\n");
241 * ATM Resource Manager Routines.
246 * Routine: atm_release_value
247 * Purpose: Release a value, if sync matches the sync count in value.
248 * Returns: KERN_SUCCESS: on Successful deletion.
249 * KERN_FAILURE: if sync value does not matches.
253 ipc_voucher_attr_manager_t __assert_only manager
,
254 mach_voucher_attr_key_t __assert_only key
,
255 mach_voucher_attr_value_handle_t value
,
256 mach_voucher_attr_value_reference_t sync
)
258 atm_value_t atm_value
= ATM_VALUE_NULL
;
260 assert(MACH_VOUCHER_ATTR_KEY_ATM
== key
);
261 assert(manager
== &atm_manager
);
263 atm_value
= HANDLE_TO_ATM_VALUE(value
);
264 if (atm_value
== VAM_DEFAULT_VALUE
) {
265 /* Return success for default value */
269 if (atm_value
->sync
!= sync
) {
273 /* Deallocate the atm value. */
274 atm_value_hash_table_delete(atm_value
);
275 atm_value_dealloc(atm_value
);
281 * Routine: atm_get_value
285 ipc_voucher_attr_manager_t __assert_only manager
,
286 mach_voucher_attr_key_t __assert_only key
,
287 mach_voucher_attr_recipe_command_t command
,
288 mach_voucher_attr_value_handle_array_t prev_values
,
289 mach_msg_type_number_t __assert_only prev_value_count
,
290 mach_voucher_attr_content_t __unused recipe
,
291 mach_voucher_attr_content_size_t __unused recipe_size
,
292 mach_voucher_attr_value_handle_t
*out_value
,
293 ipc_voucher_t
*out_value_voucher
)
295 atm_value_t atm_value
= ATM_VALUE_NULL
;
296 mach_voucher_attr_value_handle_t atm_handle
;
297 atm_task_descriptor_t task_descriptor
= ATM_TASK_DESCRIPTOR_NULL
;
299 mailbox_offset_t mailbox_offset
;
301 kern_return_t kr
= KERN_SUCCESS
;
303 assert(MACH_VOUCHER_ATTR_KEY_ATM
== key
);
304 assert(manager
== &atm_manager
);
306 /* never an out voucher */
307 *out_value_voucher
= IPC_VOUCHER_NULL
;
310 return KERN_NOT_SUPPORTED
;
314 case MACH_VOUCHER_ATTR_ATM_REGISTER
:
316 for (i
= 0; i
< prev_value_count
; i
++) {
317 atm_handle
= prev_values
[i
];
318 atm_value
= HANDLE_TO_ATM_VALUE(atm_handle
);
320 if (atm_value
== VAM_DEFAULT_VALUE
)
323 task
= current_task();
324 task_descriptor
= task
->atm_context
;
325 if (task_descriptor
!= ATM_TASK_DESCRIPTOR_NULL
) {
326 if (recipe_size
!= sizeof(mailbox_offset_t
)) {
327 kr
= KERN_INVALID_ARGUMENT
;
330 memcpy(&mailbox_offset
, recipe
, sizeof(mailbox_offset_t
));
331 if (mailbox_offset
> task_descriptor
->mailbox_array_size
) {
332 kr
= KERN_INVALID_ARGUMENT
;
336 kr
= atm_listener_insert(atm_value
, task_descriptor
, mailbox_offset
);
337 if (kr
!= KERN_SUCCESS
) {
342 /* Increment sync value. */
343 lck_mtx_lock(&atm_value
->listener_lock
);
345 lck_mtx_unlock(&atm_value
->listener_lock
);
347 *out_value
= atm_handle
;
351 *out_value
= ATM_VALUE_TO_HANDLE(VAM_DEFAULT_VALUE
);
354 case MACH_VOUCHER_ATTR_ATM_CREATE
:
356 /* Allocate a new atm value. */
357 atm_value
= atm_value_alloc_init();
358 atm_value_hash_table_insert(atm_value
);
360 if (atm_value
== ATM_VALUE_NULL
) {
361 return KERN_RESOURCE_SHORTAGE
;
364 *out_value
= ATM_VALUE_TO_HANDLE(atm_value
);
367 case MACH_VOUCHER_ATTR_ATM_NULL
:
369 kr
= KERN_INVALID_ARGUMENT
;
378 * Routine: atm_extract_content
379 * Purpose: Extract a set of aid from an array of voucher values.
380 * Returns: KERN_SUCCESS: on Success.
381 * KERN_FAILURE: one of the value is not present in the hash.
382 * KERN_NO_SPACE: insufficeint buffer provided to fill an array of aid.
386 ipc_voucher_attr_manager_t __assert_only manager
,
387 mach_voucher_attr_key_t __assert_only key
,
388 mach_voucher_attr_value_handle_array_t values
,
389 mach_msg_type_number_t value_count
,
390 mach_voucher_attr_recipe_command_t
*out_command
,
391 mach_voucher_attr_content_t out_recipe
,
392 mach_voucher_attr_content_size_t
*in_out_recipe_size
)
394 atm_value_t atm_value
;
395 mach_voucher_attr_value_handle_t atm_handle
;
398 assert(MACH_VOUCHER_ATTR_KEY_ATM
== key
);
399 assert(manager
== &atm_manager
);
401 for (i
= 0; i
< value_count
; i
++) {
402 atm_handle
= values
[i
];
403 atm_value
= HANDLE_TO_ATM_VALUE(atm_handle
);
404 if (atm_value
== VAM_DEFAULT_VALUE
)
407 if (( sizeof(aid_t
)) > *in_out_recipe_size
) {
408 *in_out_recipe_size
= 0;
409 return KERN_NO_SPACE
;
412 memcpy(&out_recipe
[0], &atm_value
->aid
, sizeof(aid_t
));
413 *out_command
= MACH_VOUCHER_ATTR_ATM_NULL
;
414 *in_out_recipe_size
= sizeof(aid_t
);
418 *in_out_recipe_size
= 0;
423 * Routine: atm_command
424 * Purpose: Execute a command against a set of ATM values.
425 * Returns: KERN_SUCCESS: On successful execution of command.
426 KERN_FAILURE: On failure.
430 ipc_voucher_attr_manager_t __assert_only manager
,
431 mach_voucher_attr_key_t __assert_only key
,
432 mach_voucher_attr_value_handle_array_t values
,
433 mach_msg_type_number_t value_count
,
434 mach_voucher_attr_command_t command
,
435 mach_voucher_attr_content_t in_content
,
436 mach_voucher_attr_content_size_t in_content_size
,
437 mach_voucher_attr_content_t out_content
,
438 mach_voucher_attr_content_size_t
*out_content_size
)
440 assert(MACH_VOUCHER_ATTR_KEY_ATM
== key
);
441 assert(manager
== &atm_manager
);
442 atm_value_t atm_value
= ATM_VALUE_NULL
;
444 aid_t
*aid_array
= NULL
;
445 mach_atm_subaid_t
*subaid_array
= NULL
;
446 uint32_t aid_array_count
= 0;
447 atm_task_descriptor_t task_descriptor
= ATM_TASK_DESCRIPTOR_NULL
;
449 uint32_t collection_flags
= ATM_ACTION_LOGFAIL
;
450 kern_return_t kr
= KERN_SUCCESS
;
453 case ATM_ACTION_COLLECT
:
454 collection_flags
= ATM_ACTION_COLLECT
;
457 case ATM_ACTION_LOGFAIL
: {
458 mach_atm_subaid_t sub_aid
= 0;
460 /* find the first non-default atm_value */
461 for (i
= 0; i
< value_count
; i
++) {
462 atm_value
= HANDLE_TO_ATM_VALUE(values
[i
]);
463 if (atm_value
!= VAM_DEFAULT_VALUE
)
467 /* if we are not able to find any atm values
468 * in stack then this call was made in error
470 if (atm_value
== NULL
) {
473 if (in_content
== NULL
|| in_content_size
< sizeof(mach_atm_subaid_t
) ){
474 return KERN_INVALID_ARGUMENT
;
477 sub_aid
= *(mach_atm_subaid_t
*)(void *)in_content
;
478 *out_content_size
= 0;
479 kr
= atm_invoke_collection(atm_value
, sub_aid
, collection_flags
);
483 case ATM_FIND_MIN_SUB_AID
:
484 if ((in_content_size
/sizeof(aid_t
)) > (*out_content_size
/sizeof(mach_atm_subaid_t
)))
487 aid_array_count
= in_content_size
/ sizeof(aid_t
);
488 if (aid_array_count
> AID_ARRAY_COUNT_MAX
)
491 aid_array
= (aid_t
*) kalloc(aid_array_count
* sizeof(aid_t
));
492 if (aid_array
== NULL
)
493 return KERN_NO_SPACE
;
495 subaid_array
= (mach_atm_subaid_t
*) kalloc(aid_array_count
* sizeof(mach_atm_subaid_t
));
496 if (subaid_array
== NULL
) {
497 kfree(aid_array
, aid_array_count
* sizeof(aid_t
));
498 return KERN_NO_SPACE
;
501 memcpy(aid_array
, in_content
, aid_array_count
* sizeof(aid_t
));
502 atm_get_min_sub_aid_array(aid_array
, subaid_array
, aid_array_count
);
504 memcpy(out_content
, subaid_array
, aid_array_count
* sizeof(mach_atm_subaid_t
));
505 *out_content_size
= aid_array_count
* sizeof(mach_atm_subaid_t
);
507 kfree(aid_array
, aid_array_count
* sizeof(aid_t
));
508 kfree(subaid_array
, aid_array_count
* sizeof(mach_atm_subaid_t
));
513 case ATM_ACTION_UNREGISTER
:
514 /* find the first non-default atm_value */
515 for (i
= 0; i
< value_count
; i
++) {
516 atm_value
= HANDLE_TO_ATM_VALUE(values
[i
]);
517 if (atm_value
!= VAM_DEFAULT_VALUE
)
521 /* if we are not able to find any atm values
522 * in stack then this call was made in error
524 if (atm_value
== NULL
) {
527 if (in_content
== NULL
|| in_content_size
!= sizeof(mailbox_offset_t
)){
528 return KERN_INVALID_ARGUMENT
;
531 mailbox_offset_t mailbox_offset
;
532 memcpy(&mailbox_offset
, in_content
, sizeof(mailbox_offset_t
));
533 task
= current_task();
534 task_descriptor
= task
->atm_context
;
536 kr
= atm_value_unregister(atm_value
, task_descriptor
, mailbox_offset
);
541 kr
= KERN_INVALID_ARGUMENT
;
551 ipc_voucher_attr_manager_t __assert_only manager
)
553 assert(manager
== &atm_manager
);
558 * Routine: atm_invoke_collection
559 * Purpose: Sends a notification with array of memory buffer.
560 * Note: may block till user daemon responds.
563 atm_invoke_collection(
564 atm_value_t atm_value
,
565 subaid_t sub_activity_id
,
568 aid_t aid
= atm_value
->aid
;
569 kern_return_t kr
= KERN_SUCCESS
;
570 uint32_t array_count
= 0, i
= 0, requestor_index
= 0;
571 uint64_t *sizes_array
= NULL
;
572 atm_link_object_t link_object
= NULL
;
573 mach_port_t
*mem_array
= NULL
;
574 boolean_t need_swap_first
= FALSE
;
575 atm_task_descriptor_t requesting_descriptor
= current_task()->atm_context
;
577 lck_mtx_lock(&atm_value
->listener_lock
);
578 array_count
= atm_value
->listener_count
;
579 lck_mtx_unlock(&atm_value
->listener_lock
);
581 if (array_count
== 0){
585 mem_array
= kalloc(sizeof(mach_port_t
) * array_count
);
586 if (mem_array
== NULL
){
587 return KERN_NO_SPACE
;
590 sizes_array
= kalloc(sizeof(uint64_t) * array_count
);
591 if (sizes_array
== NULL
){
592 kfree(mem_array
, sizeof(mach_port_t
) * array_count
);
593 return KERN_NO_SPACE
;
596 lck_mtx_lock(&atm_value
->listener_lock
);
597 queue_iterate(&atm_value
->listeners
, link_object
, atm_link_object_t
, listeners_element
) {
598 if (i
>= array_count
){
602 if (!need_swap_first
&& requesting_descriptor
== link_object
->descriptor
){
603 assert(requesting_descriptor
!= NULL
);
605 need_swap_first
= TRUE
;
608 sizes_array
[i
] = link_object
->descriptor
->trace_buffer_size
;
609 mem_array
[i
] = ipc_port_copy_send(link_object
->descriptor
->trace_buffer
);
610 if (!IPC_PORT_VALID(mem_array
[i
])){
615 lck_mtx_unlock(&atm_value
->listener_lock
);
618 * Swap the position of requesting task ahead, diagnostics can
619 * process its buffers the first.
621 if (need_swap_first
&& requestor_index
!= 0){
622 assert(requestor_index
< array_count
);
623 mach_port_t tmp_port
= mem_array
[0];
624 uint64_t tmp_size
= sizes_array
[0];
625 mem_array
[0] = mem_array
[requestor_index
];
626 sizes_array
[0] = sizes_array
[requestor_index
];
627 mem_array
[requestor_index
] = tmp_port
;
628 sizes_array
[requestor_index
] = tmp_size
;
632 kr
= atm_send_user_notification(aid
, sub_activity_id
, mem_array
, sizes_array
, i
, flags
);
635 kfree(mem_array
, sizeof(mach_port_t
) * array_count
);
636 kfree(sizes_array
, sizeof(uint64_t) * array_count
);
642 * Routine: atm_send_user_notification
643 * Purpose: Make an upcall to user space daemon if its listening for atm notifications.
644 * Returns: KERN_SUCCESS for successful delivery.
645 * KERN_FAILURE if port is dead or NULL.
648 atm_send_user_notification(
651 mach_port_t
*buffers_array
,
652 uint64_t *sizes_array
,
653 mach_msg_type_number_t count
,
656 mach_port_t user_port
;
658 error
= host_get_atm_notification_port(host_priv_self(), &user_port
);
659 if ((error
!= KERN_SUCCESS
) || !IPC_PORT_VALID(user_port
)) {
663 return atm_collect_trace_info(user_port
, aid
, subaid
, flags
, buffers_array
, count
, sizes_array
, count
);
667 * Routine: atm_send_proc_inspect_notification
668 * Purpose: Make an upcall to user space daemon if its listening for trace
669 * notifications for per process inspection.
670 * Returns: KERN_SUCCESS for successful delivery.
671 * KERN_FAILURE if port is dead or NULL.
675 atm_send_proc_inspect_notification(
678 uint64_t traced_uniqueid
)
680 mach_port_t user_port
= MACH_PORT_NULL
;
681 mach_port_t memory_port
= MACH_PORT_NULL
;
682 atm_task_descriptor_t task_descriptor
= ATM_TASK_DESCRIPTOR_NULL
;
683 uint64_t buffer_size
= 0;
686 /* look for the requested memory in target task */
688 return KERN_INVALID_TASK
;
691 if (task
->atm_context
){
692 task_descriptor
= task
->atm_context
;
693 atm_descriptor_get_reference(task_descriptor
);
697 if (task_descriptor
== ATM_TASK_DESCRIPTOR_NULL
){
701 memory_port
= ipc_port_copy_send(task_descriptor
->trace_buffer
);
702 buffer_size
= task_descriptor
->trace_buffer_size
;
703 atm_task_descriptor_dealloc(task_descriptor
);
705 /* get the communication port */
706 error
= host_get_atm_notification_port(host_priv_self(), &user_port
);
707 if ((error
!= KERN_SUCCESS
) || !IPC_PORT_VALID(user_port
)) {
708 ipc_port_release_send(memory_port
);
712 return atm_inspect_process_buffer(user_port
, traced_pid
, traced_uniqueid
, buffer_size
, memory_port
);
716 * Routine: atm_value_alloc_init
717 * Purpose: Allocates an atm value struct and initialize it.
718 * Returns: atm_value_t: On Success with a sync count on atm_value.
719 * ATM_VALUE_NULL: On failure.
722 atm_value_alloc_init()
724 atm_value_t new_atm_value
= ATM_VALUE_NULL
;
726 new_atm_value
= (atm_value_t
) zalloc(atm_value_zone
);
727 if (new_atm_value
== ATM_VALUE_NULL
)
728 panic("Ran out of ATM values structure.\n\n");
730 new_atm_value
->aid
= get_aid();
731 queue_init(&new_atm_value
->listeners
);
732 new_atm_value
->sync
= 1;
733 new_atm_value
->listener_count
= 0;
734 new_atm_value
->reference_count
= 1;
735 lck_mtx_init(&new_atm_value
->listener_lock
, &atm_lock_grp
, &atm_lock_attr
);
737 #if DEVELOPMENT || DEBUG
738 lck_mtx_lock(&atm_values_list_lock
);
739 queue_enter(&atm_values_list
, new_atm_value
, atm_value_t
, value_elt
);
740 lck_mtx_unlock(&atm_values_list_lock
);
742 return new_atm_value
;
748 * Purpose: Increment the global aid counter and return it.
755 aid
= (aid_t
)OSIncrementAtomic64((SInt64
*)&global_aid
);
761 * Routine: atm_value_dealloc
762 * Purpose: Drops the reference on atm value and deallocates.
763 * Deletes all the listeners on deallocation.
767 atm_value_dealloc(atm_value_t atm_value
)
769 lck_mtx_lock(&atm_value
->listener_lock
);
771 atm_value
->reference_count
--;
772 assert(atm_value
->reference_count
>= 0);
774 if (atm_value
->reference_count
> 0) {
775 lck_mtx_unlock(&atm_value
->listener_lock
);
779 lck_mtx_unlock(&atm_value
->listener_lock
);
781 /* Free up the atm value and also remove all the listeners. */
782 atm_listener_delete_all(atm_value
);
784 lck_mtx_destroy(&atm_value
->listener_lock
, &atm_lock_grp
);
786 #if DEVELOPMENT || DEBUG
787 lck_mtx_lock(&atm_values_list_lock
);
788 queue_remove(&atm_values_list
, atm_value
, atm_value_t
, value_elt
);
789 lck_mtx_unlock(&atm_values_list_lock
);
791 zfree(atm_value_zone
, atm_value
);
797 * Routine: atm_hash_table_init
798 * Purpose: Initialize the atm aid hash table.
802 atm_hash_table_init()
806 for (i
= 0; i
< ATM_MAX_HASH_TABLE_SIZE
; i
++) {
807 queue_init(&atm_value_hash_table
[i
].hash_list
);
808 lck_mtx_init(&atm_value_hash_table
[i
].hash_list_lock
, &atm_lock_grp
, &atm_lock_attr
);
814 * Routine: atm_value_hash_table_insert
815 * Purpose: Insert an atm value in the hash table.
819 atm_value_hash_table_insert(atm_value_t new_atm_value
)
822 atm_value_hash_t hash_list_head
;
823 aid_t aid
= new_atm_value
->aid
;
825 hash_index
= AID_TO_HASH(aid
);
826 hash_list_head
= &atm_value_hash_table
[hash_index
];
828 lck_mtx_lock(&hash_list_head
->hash_list_lock
);
829 queue_enter(&hash_list_head
->hash_list
, new_atm_value
, atm_value_t
, vid_hash_elt
);
830 lck_mtx_unlock(&hash_list_head
->hash_list_lock
);
835 * Routine: atm_value_hash_table_delete
836 * Purpose: Delete the atm value from the hash table.
840 atm_value_hash_table_delete(atm_value_t atm_value
)
843 atm_value_hash_t hash_list_head
;
844 aid_t aid
= atm_value
->aid
;
846 hash_index
= AID_TO_HASH(aid
);
847 hash_list_head
= &atm_value_hash_table
[hash_index
];
849 lck_mtx_lock(&hash_list_head
->hash_list_lock
);
850 queue_remove(&hash_list_head
->hash_list
, atm_value
, atm_value_t
, vid_hash_elt
);
851 lck_mtx_unlock(&hash_list_head
->hash_list_lock
);
856 * Routine: get_atm_value_from_aid
857 * Purpose: Search a given aid in atm value hash table and
858 * return the atm value stucture.
859 * Returns: atm value structure if aid found.
860 * ATM_VALUE_NULL: If aid not found in atm value hash table.
863 get_atm_value_from_aid(aid_t aid
)
866 atm_value_hash_t hash_list_head
;
869 hash_index
= AID_TO_HASH(aid
);
870 hash_list_head
= &atm_value_hash_table
[hash_index
];
872 /* Lock the atm list and search for the aid. */
873 lck_mtx_lock(&hash_list_head
->hash_list_lock
);
875 queue_iterate(&hash_list_head
->hash_list
, next
, atm_value_t
, vid_hash_elt
) {
876 if (next
->aid
== aid
) {
878 * Aid found. Incerease ref count and return
879 * the atm value structure.
881 atm_value_get_ref(next
);
882 lck_mtx_unlock(&hash_list_head
->hash_list_lock
);
886 lck_mtx_unlock(&hash_list_head
->hash_list_lock
);
887 return ATM_VALUE_NULL
;
892 * Routine: atm_value_get_ref
893 * Purpose: Get a reference on atm value.
897 atm_value_get_ref(atm_value_t atm_value
)
899 lck_mtx_lock(&atm_value
->listener_lock
);
900 atm_value
->reference_count
++;
901 lck_mtx_unlock(&atm_value
->listener_lock
);
906 * Routine: atm_listener_insert
907 * Purpose: Insert a listener to an atm value.
908 * Returns: KERN_SUCCESS on success.
909 * KERN_FAILURE if the task is already present as a listener.
913 atm_value_t atm_value
,
914 atm_task_descriptor_t task_descriptor
,
915 mailbox_offset_t mailbox_offset
)
917 atm_link_object_t new_link_object
;
918 atm_link_object_t next
;
919 void *mailbox
= (void *)((char *)task_descriptor
->mailbox_kernel_addr
+ mailbox_offset
);
921 new_link_object
= (atm_link_object_t
) zalloc(atm_link_objects_zone
);
922 new_link_object
->descriptor
= task_descriptor
;
923 new_link_object
->reference_count
= 1;
924 new_link_object
->flags
= 0;
925 new_link_object
->mailbox
= mailbox
;
927 /* Get a reference on the task descriptor */
928 atm_descriptor_get_reference(task_descriptor
);
930 /* Check if the task mailbox is already on the listener list */
931 lck_mtx_lock(&atm_value
->listener_lock
);
932 queue_iterate(&atm_value
->listeners
, next
, atm_link_object_t
, listeners_element
) {
933 if (next
->descriptor
== task_descriptor
) {
935 * Replace the mailbox with the new one, the old mailbox is anyways on unregister path.
936 * There is a race when get_min_sub_aid would cache the mailbox, and this function will
937 * replace it. It would just behave as if the get value call happened after get_min_sub_aid
938 * was already completed.
940 next
->mailbox
= mailbox
;
941 lck_mtx_unlock(&atm_value
->listener_lock
);
942 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_GETVALUE_INFO
, (ATM_VALUE_REPLACED
))) | DBG_FUNC_NONE
,
943 atm_value
, atm_value
->aid
, mailbox_offset
, 0, 0);
945 /* Drop the extra reference on task descriptor taken by this function. */
946 atm_task_descriptor_dealloc(task_descriptor
);
947 zfree(atm_link_objects_zone
, new_link_object
);
951 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_GETVALUE_INFO
, (ATM_VALUE_ADDED
))) | DBG_FUNC_NONE
,
952 atm_value
, atm_value
->aid
, mailbox_offset
, 0, 0);
954 queue_enter(&atm_value
->listeners
, new_link_object
, atm_link_object_t
, listeners_element
);
955 atm_value
->listener_count
++;
956 lck_mtx_unlock(&atm_value
->listener_lock
);
962 * Routine: atm_listener_delete_all
963 * Purpose: Deletes all the listeners for an atm value.
967 atm_listener_delete_all(atm_value_t atm_value
)
969 atm_link_object_t next
;
971 while(!queue_empty(&atm_value
->listeners
)) {
972 queue_remove_first(&atm_value
->listeners
, next
, atm_link_object_t
, listeners_element
);
974 /* Drops the reference on the link object */
975 atm_link_dealloc(next
);
981 * Routine: atm_listener_delete
982 * Purpose: Deletes a listerner for an atm value.
983 * Returns: KERN_SUCCESS on successful unregister.
984 * KERN_INVALID_VALUE on finding a different mailbox.
985 * KERN_FAILURE on failure.
989 atm_value_t atm_value
,
990 atm_task_descriptor_t task_descriptor
,
991 mailbox_offset_t mailbox_offset
)
993 queue_head_t free_listeners
;
994 atm_link_object_t next
, elem
;
995 void *mailbox
= (void *)((char *)task_descriptor
->mailbox_kernel_addr
+ mailbox_offset
);
996 kern_return_t kr
= KERN_FAILURE
;
998 queue_init(&free_listeners
);
1000 lck_mtx_lock(&atm_value
->listener_lock
);
1002 next
= (atm_link_object_t
)(void *) queue_first(&atm_value
->listeners
);
1003 while (!queue_end(&atm_value
->listeners
, (queue_entry_t
)next
)) {
1005 next
= (atm_link_object_t
)(void *) queue_next(&next
->listeners_element
);
1007 if (elem
->descriptor
== task_descriptor
) {
1008 if (elem
->mailbox
== mailbox
) {
1009 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_UNREGISTER_INFO
,
1010 (ATM_VALUE_UNREGISTERED
))) | DBG_FUNC_NONE
,
1011 atm_value
, atm_value
->aid
, mailbox_offset
, 0, 0);
1012 queue_remove(&atm_value
->listeners
, elem
, atm_link_object_t
, listeners_element
);
1013 queue_enter(&free_listeners
, elem
, atm_link_object_t
, listeners_element
);
1014 atm_value
->listener_count
--;
1018 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_UNREGISTER_INFO
,
1019 (ATM_VALUE_DIFF_MAILBOX
))) | DBG_FUNC_NONE
,
1020 atm_value
, atm_value
->aid
, 0, 0, 0);
1021 kr
= KERN_INVALID_VALUE
;
1026 lck_mtx_unlock(&atm_value
->listener_lock
);
1028 while(!queue_empty(&free_listeners
)) {
1029 queue_remove_first(&free_listeners
, next
, atm_link_object_t
, listeners_element
);
1031 /* Drops the reference on the link object */
1032 atm_link_dealloc(next
);
1039 * Routine: atm_descriptor_alloc_init
1040 * Purpose: Allocate an atm task descriptor and initialize it and takes a reference.
1041 * Returns: atm task descriptor: On success.
1044 static atm_task_descriptor_t
1045 atm_task_descriptor_alloc_init(
1046 mach_port_t trace_buffer
,
1047 uint64_t buffer_size
,
1048 void * mailbox_addr
,
1049 uint64_t mailbox_array_size
,
1050 task_t __assert_only task
)
1052 atm_task_descriptor_t new_task_descriptor
;
1054 new_task_descriptor
= (atm_task_descriptor_t
) zalloc(atm_descriptors_zone
);
1056 new_task_descriptor
->trace_buffer
= trace_buffer
;
1057 new_task_descriptor
->trace_buffer_size
= buffer_size
;
1058 new_task_descriptor
->mailbox_array_size
= mailbox_array_size
;
1059 new_task_descriptor
->mailbox_kernel_addr
= mailbox_addr
;
1060 new_task_descriptor
->reference_count
= 1;
1061 new_task_descriptor
->flags
= 0;
1062 lck_mtx_init(&new_task_descriptor
->lock
, &atm_lock_grp
, &atm_lock_attr
);
1064 #if DEVELOPMENT || DEBUG
1065 new_task_descriptor
->task
= task
;
1066 lck_mtx_lock(&atm_descriptors_list_lock
);
1067 queue_enter(&atm_descriptors_list
, new_task_descriptor
, atm_task_descriptor_t
, descriptor_elt
);
1068 lck_mtx_unlock(&atm_descriptors_list_lock
);
1071 return new_task_descriptor
;
1076 * Routine: atm_descriptor_get_reference
1077 * Purpose: Get a reference count on task descriptor.
1081 atm_descriptor_get_reference(atm_task_descriptor_t task_descriptor
)
1083 lck_mtx_lock(&task_descriptor
->lock
);
1084 task_descriptor
->reference_count
++;
1085 lck_mtx_unlock(&task_descriptor
->lock
);
1090 * Routine: atm_task_descriptor_dealloc
1091 * Prupose: Drops the reference on atm descriptor.
1095 atm_task_descriptor_dealloc(atm_task_descriptor_t task_descriptor
)
1097 lck_mtx_lock(&task_descriptor
->lock
);
1098 task_descriptor
->reference_count
--;
1099 assert(task_descriptor
->reference_count
>= 0);
1100 if (task_descriptor
->reference_count
> 0) {
1101 lck_mtx_unlock(&task_descriptor
->lock
);
1105 #if DEVELOPMENT || DEBUG
1106 lck_mtx_lock(&atm_descriptors_list_lock
);
1107 queue_remove(&atm_descriptors_list
, task_descriptor
, atm_task_descriptor_t
, descriptor_elt
);
1108 lck_mtx_unlock(&atm_descriptors_list_lock
);
1110 mach_vm_deallocate(kernel_map
, (mach_vm_address_t
)task_descriptor
->mailbox_kernel_addr
,
1111 task_descriptor
->mailbox_array_size
);
1112 task_descriptor
->mailbox_kernel_addr
= NULL
;
1113 task_descriptor
->mailbox_array_size
= 0;
1114 /* release the send right for the named memory entry */
1115 ipc_port_release_send(task_descriptor
->trace_buffer
);
1116 lck_mtx_unlock(&task_descriptor
->lock
);
1117 lck_mtx_destroy(&task_descriptor
->lock
, &atm_lock_grp
);
1118 zfree(atm_descriptors_zone
, task_descriptor
);
1124 * Routine: atm_link_get_reference
1125 * Purpose: Get a reference count on atm link object.
1129 atm_link_get_reference(atm_link_object_t link_object
)
1131 atm_link_object_reference_internal(link_object
);
1136 * Routine: atm_link_dealloc
1137 * Prupose: Drops the reference on link object.
1141 atm_link_dealloc(atm_link_object_t link_object
)
1143 if (0 < atm_link_object_release_internal(link_object
)) {
1147 assert(link_object
->reference_count
== 0);
1149 /* Drop the reference on atm task descriptor. */
1150 atm_task_descriptor_dealloc(link_object
->descriptor
);
1151 zfree(atm_link_objects_zone
, link_object
);
1156 * Routine: atm_register_trace_memory
1157 * Purpose: Registers trace memory for a task.
1158 * Returns: KERN_SUCCESS: on Success.
1159 * KERN_FAILURE: on Error.
1162 atm_register_trace_memory(
1164 uint64_t trace_buffer_address
,
1165 uint64_t buffer_size
,
1166 uint64_t mailbox_array_size
)
1168 atm_task_descriptor_t task_descriptor
;
1169 mach_port_t trace_buffer
= MACH_PORT_NULL
;
1170 mach_vm_offset_t mailbox_kernel_ptr
= 0;
1171 kern_return_t kr
= KERN_SUCCESS
;
1174 return KERN_NOT_SUPPORTED
;
1176 if (task
!= current_task())
1177 return KERN_INVALID_ARGUMENT
;
1179 if (task
->atm_context
!= NULL
1180 || (void *)trace_buffer_address
== NULL
1182 || (buffer_size
& PAGE_MASK
) != 0
1183 || buffer_size
> MAX_TRACE_BUFFER_SIZE
1184 || mailbox_array_size
== 0
1185 || mailbox_array_size
>= buffer_size
1186 || mailbox_array_size
> MAX_MAILBOX_SIZE
1187 || mailbox_array_size
& PAGE_MIN_MASK
) {
1188 return KERN_INVALID_ARGUMENT
;
1191 vm_map_t map
= current_map();
1192 memory_object_size_t mo_size
= (memory_object_size_t
) buffer_size
;
1193 kr
= mach_make_memory_entry_64(map
,
1195 (mach_vm_offset_t
)trace_buffer_address
,
1199 if (kr
!= KERN_SUCCESS
)
1202 kr
= mach_vm_map(kernel_map
,
1203 &mailbox_kernel_ptr
,
1215 if (kr
!= KERN_SUCCESS
){
1216 ipc_port_release_send(trace_buffer
);
1220 task_descriptor
= atm_task_descriptor_alloc_init(trace_buffer
, buffer_size
, (void *)mailbox_kernel_ptr
, mailbox_array_size
, task
);
1221 if (task_descriptor
== ATM_TASK_DESCRIPTOR_NULL
) {
1222 ipc_port_release_send(trace_buffer
);
1223 mach_vm_deallocate(kernel_map
, (mach_vm_address_t
)mailbox_kernel_ptr
, mailbox_array_size
);
1224 return KERN_NO_SPACE
;
1228 if (task
->atm_context
== NULL
) {
1229 task
->atm_context
= task_descriptor
;
1236 if (kr
!= KERN_SUCCESS
) {
1237 /* undo the mapping and allocations since we failed to hook descriptor to task */
1238 atm_task_descriptor_dealloc(task_descriptor
);
1240 return KERN_SUCCESS
;
1245 * Routine: atm_get_min_sub_aid_array
1246 * Purpose: For an array of aid, lookup the atm value and fill the minimum subaid.
1250 atm_get_min_sub_aid_array(
1252 mach_atm_subaid_t
*subaid_array
,
1255 atm_value_t atm_value
;
1258 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_SUBAID_INFO
, (ATM_MIN_CALLED
))) | DBG_FUNC_START
,
1261 for (i
= 0; i
< count
; i
++) {
1262 atm_value
= get_atm_value_from_aid(aid_array
[i
]);
1263 if (atm_value
== ATM_VALUE_NULL
) {
1264 subaid_array
[i
] = ATM_SUBAID32_MAX
;
1267 subaid_array
[i
] = atm_get_min_sub_aid(atm_value
);
1268 atm_value_dealloc(atm_value
);
1271 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_SUBAID_INFO
, (ATM_MIN_CALLED
))) | DBG_FUNC_END
,
1278 * Routine: atm_get_min_sub_aid
1279 * Purpose: Walk the list of listeners and get the min sub-aid for an activity id.
1280 * Returns: Minimum sub-aid to keep.
1281 * Note: Unlock the listener lock before accessing the mailbox, since it may page fault and
1282 * might take long time. Also cleans the listeners list for the tasks which are dead
1283 * and atm_task_descriptors do not hold any useful data.
1285 static mach_atm_subaid_t
1286 atm_get_min_sub_aid(atm_value_t atm_value
)
1288 int32_t i
= 0, j
, freed_count
= 0, dead_but_not_freed
= 0;
1289 int32_t listener_count
;
1290 atm_subaid32_t min_subaid
= ATM_SUBAID32_MAX
, subaid
, max_subaid
;
1291 atm_link_object_t
*link_object_array
= NULL
;
1292 atm_link_object_t next
, elem
;
1293 queue_head_t free_listeners
;
1295 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_SUBAID_INFO
, (ATM_MIN_LINK_LIST
))) | DBG_FUNC_START
,
1298 lck_mtx_lock(&atm_value
->listener_lock
);
1299 listener_count
= atm_value
->listener_count
;
1300 lck_mtx_unlock(&atm_value
->listener_lock
);
1302 /* separate memory access from locked iterate since memory read may fault */
1303 link_object_array
= (atm_link_object_t
*) kalloc(sizeof(atm_link_object_t
) * listener_count
);
1304 if (link_object_array
== NULL
) {
1308 /* Iterate the list and take a ref on link objects and store it in an array */
1309 lck_mtx_lock(&atm_value
->listener_lock
);
1310 queue_iterate(&atm_value
->listeners
, next
, atm_link_object_t
, listeners_element
) {
1311 /* Additional listener are added between the allocation of array and iterating the list */
1312 if (i
>= listener_count
)
1315 /* Get a ref on the link object */
1316 atm_link_get_reference(next
);
1317 link_object_array
[i
] = (atm_link_object_t
)next
;
1320 lck_mtx_unlock(&atm_value
->listener_lock
);
1323 /* Iterate the array to find the min */
1324 for (i
= 0; i
< j
; i
++) {
1325 /* Ignore the min value of the dead processes. */
1326 if (link_object_array
[i
]->descriptor
->flags
== ATM_TASK_DEAD
)
1328 /* Dereference the mailbox to get the min subaid */
1329 subaid
= *((atm_subaid32_t
*)link_object_array
[i
]->mailbox
);
1330 if (subaid
< min_subaid
)
1331 min_subaid
= subaid
;
1335 * Mark the link object that can be freed, and release the ref on the link object
1336 * Mark the link object of dead task free after the dead task descriptor count
1337 * increases than ATM_LIST_DEAD_MAX.
1339 for (i
= j
- 1; i
>= 0; i
--) {
1340 if (link_object_array
[i
]->descriptor
->flags
== ATM_TASK_DEAD
) {
1341 if (dead_but_not_freed
> ATM_LIST_DEAD_MAX
) {
1342 link_object_array
[i
]->flags
= ATM_LINK_REMOVE
;
1345 max_subaid
= *(((atm_subaid32_t
*)link_object_array
[i
]->mailbox
) + 1);
1346 if (max_subaid
< min_subaid
) {
1347 link_object_array
[i
]->flags
= ATM_LINK_REMOVE
;
1350 dead_but_not_freed
++;
1354 atm_link_dealloc(link_object_array
[i
]);
1355 link_object_array
[i
] = NULL
;
1358 /* Check if the number of live entries in list is less than maxproc */
1359 assert((j
- (freed_count
+ dead_but_not_freed
)) <= maxproc
);
1361 kfree(link_object_array
, (sizeof(atm_link_object_t
) * listener_count
));
1363 /* Remove the marked link objects from the list */
1364 lck_mtx_lock(&atm_value
->listener_lock
);
1366 queue_init(&free_listeners
);
1367 next
= (atm_link_object_t
)(void *) queue_first(&atm_value
->listeners
);
1368 while (!queue_end(&atm_value
->listeners
, (queue_entry_t
)next
)) {
1370 next
= (atm_link_object_t
)(void *) queue_next(&next
->listeners_element
);
1372 if (elem
->flags
== ATM_LINK_REMOVE
) {
1373 queue_remove(&atm_value
->listeners
, elem
, atm_link_object_t
, listeners_element
);
1374 queue_enter(&free_listeners
, elem
, atm_link_object_t
, listeners_element
);
1375 atm_value
->listener_count
--;
1378 lck_mtx_unlock(&atm_value
->listener_lock
);
1380 /* Free the link objects */
1381 while(!queue_empty(&free_listeners
)) {
1382 queue_remove_first(&free_listeners
, next
, atm_link_object_t
, listeners_element
);
1384 /* Drops the reference on the link object */
1385 atm_link_dealloc(next
);
1388 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (ATM_CODE(ATM_SUBAID_INFO
, (ATM_MIN_LINK_LIST
))) | DBG_FUNC_END
,
1389 j
, freed_count
, dead_but_not_freed
, 0, 0);
1391 /* explicitly upgrade uint32_t to 64 bit mach size */
1392 return CAST_DOWN(mach_atm_subaid_t
, min_subaid
);
1397 * Routine: atm_value_unregister
1398 * Purpose: Unregisters a process from an activity id.
1399 * Returns: KERN_SUCCESS on successful unregister.
1400 * KERN_INVALID_VALUE on finding a diff mailbox.
1401 * KERN_FAILURE on failure.
1403 static kern_return_t
1404 atm_value_unregister(
1405 atm_value_t atm_value
,
1406 atm_task_descriptor_t task_descriptor
,
1407 mailbox_offset_t mailbox_offset
)
1411 if (task_descriptor
== ATM_TASK_DESCRIPTOR_NULL
)
1412 return KERN_INVALID_ARGUMENT
;
1413 if (mailbox_offset
> task_descriptor
->mailbox_array_size
)
1414 return KERN_INVALID_ARGUMENT
;
1416 kr
= atm_listener_delete(atm_value
, task_descriptor
, mailbox_offset
);
1421 atm_task_descriptor_destroy(atm_task_descriptor_t task_descriptor
)
1423 /* Mark the task dead in the task descriptor to make task descriptor eligible for cleanup. */
1424 lck_mtx_lock(&task_descriptor
->lock
);
1425 task_descriptor
->flags
= ATM_TASK_DEAD
;
1426 lck_mtx_unlock(&task_descriptor
->lock
);
1428 atm_task_descriptor_dealloc(task_descriptor
);