2 * Copyright (c) 2019 Apple Computer, 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 <darwintest.h>
30 #include <darwintest_multiprocess.h>
37 #include <dispatch/dispatch.h>
41 #include <sys/ioctl.h>
42 #include <sys/socket.h>
43 #include <sys/kern_event.h>
44 #include <sys/sysctl.h>
45 #include "../bsd/sys/kern_memorystatus.h"
52 struct kern_event_msg
*ev_msg
= (struct kern_event_msg
*)&buf
[0];
54 status
= recv(so
, &buf
, sizeof(buf
), 0);
56 T_LOG("recv() failed: %s", strerror(errno
));
60 if (ev_msg
->total_size
> status
) {
61 T_LOG("missed SYSPROTO_EVENT event, buffer not big enough");
65 if (ev_msg
->vendor_code
== KEV_VENDOR_APPLE
&& ev_msg
->kev_class
== KEV_SYSTEM_CLASS
&& ev_msg
->kev_subclass
== KEV_DIRTYSTATUS_SUBCLASS
) {
66 if (ev_msg
->event_code
== kDirtyStatusChangeNote
) {
67 dirty_status_change_event_t
*ev_data
= (dirty_status_change_event_t
*)&ev_msg
->event_data
;
68 switch (ev_data
->dsc_event_type
) {
69 case kDirtyStatusChangedClean
:
70 case kDirtyStatusChangedDirty
:
73 T_LOG("Unknown event type %d", ev_data
->dsc_event_type
);
76 T_LOG("Process: %s, status: %s, pages: %llu, timestamp: %llu, priority: %d",
77 ev_data
->dsc_process_name
, ev_data
->dsc_event_type
== kDirtyStatusChangedDirty
? "dirty" : "clean", ev_data
->dsc_pages
, ev_data
->dsc_time
, ev_data
->dsc_priority
);
80 T_LOG("Ignoring message with code: %d", ev_msg
->event_code
);
83 T_LOG(("Unexpected event with vendor code: %d"), ev_msg
->vendor_code
);
90 T_DECL(dirtiness_tracking
,
91 "Check if we are able to receive dirtiness-tracking events from the kernel")
94 struct kev_request kev_req
;
95 int enable_sysctl
= 1;
97 // First try enabling the dirtystatus_tracking sysctl if available
98 if (sysctlbyname("kern.dirtystatus_tracking_enabled", NULL
, NULL
, &enable_sysctl
, sizeof(enable_sysctl
)) != 0) {
99 T_SKIP("The kern.dirtystatus_tracking_enabled sysctl is not available, skipping...");
101 /* Open an event socket */
102 so
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
104 /* establish filter to return all events */
105 kev_req
.vendor_code
= KEV_VENDOR_APPLE
;
106 kev_req
.kev_class
= KEV_SYSTEM_CLASS
;/* Not used if vendor_code is 0 */
107 kev_req
.kev_subclass
= KEV_DIRTYSTATUS_SUBCLASS
; /* Not used if either kev_class OR vendor_code are 0 */
108 status
= ioctl(so
, SIOCSKEVFILT
, &kev_req
);
111 T_FAIL("could not establish event filter, ioctl() failed: %s", strerror(errno
));
115 T_FAIL("could not open event socket, socket() failed: %s", strerror(errno
));
122 status
= ioctl(so
, FIONBIO
, &yes
);
126 T_FAIL( "could not set non-blocking io, ioctl() failed: %s", strerror(errno
));
132 T_FAIL("memory monitor disabled");
137 dispatch_queue_t queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
139 dispatch_source_t read_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
,
140 (uintptr_t)so
, 0, queue
);
142 dispatch_source_t timer
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, queue
);
143 dispatch_source_set_timer(timer
, dispatch_time(DISPATCH_TIME_NOW
, 15 * NSEC_PER_SEC
), 5 * NSEC_PER_SEC
, 1 * NSEC_PER_SEC
);
145 dispatch_source_set_event_handler(read_source
, ^{
146 int rc
= read_event(so
);
148 dispatch_source_cancel(read_source
);
150 T_PASS("Dirtiness-tracking Kevent successfully received");
152 T_FAIL("Could not read from the system socket, aborting data collection");
157 dispatch_source_set_cancel_handler(read_source
, ^{
159 dispatch_cancel(timer
);
163 dispatch_activate(read_source
);
165 dispatch_source_set_event_handler(timer
, ^{
166 dispatch_cancel(read_source
);
167 T_FAIL("Timeout expired, no events received from the kernel");
170 dispatch_activate(timer
);