* do a lookup on /tmp/b, you'd acquire an entirely different record's resource
* fork.
*
- * As a result, we use the fileid, which should be invariant for the lifetime
- * of the cnode (possibly barring calls to exchangedata).
+ * As a result, we use the fileid, which should be invariant for the lifetime
+ * of the cnode (possibly barring calls to exchangedata).
+ *
+ * Addendum: We can't do the above for HFS standard since we aren't guaranteed to
+ * have thread records for files. They were only required for directories. So
+ * we need to do the lookup with the catalog name. This is OK since hardlinks were
+ * never allowed on HFS standard.
*/
- error = cat_idlookup (hfsmp, cp->c_attr.ca_fileid, 0, 1, NULL, NULL, &rsrcfork);
+ if (hfsmp->hfs_flags & HFS_STANDARD) {
+ /*
+ * HFS standard only:
+ *
+ * Get the resource fork for this item via catalog lookup
+ * since HFS standard was case-insensitive only. We don't want the
+ * descriptor; just the fork data here.
+ */
+ error = cat_lookup (hfsmp, descptr, 1, (struct cat_desc*)NULL,
+ (struct cat_attr*)NULL, &rsrcfork, NULL);
+ }
+ else {
+ error = cat_idlookup (hfsmp, cp->c_fileid, 0, 1, NULL, NULL, &rsrcfork);
+ }
hfs_systemfile_unlock(hfsmp, lockflags);
if (error) {
*/
event = (u_int)hint & NOTE_PCTRLMASK;
+ /*
+ * termination lifecycle events can happen while a debugger
+ * has reparented a process, in which case notifications
+ * should be quashed except to the tracing parent. When
+ * the debugger reaps the child (either via wait4(2) or
+ * process exit), the child will be reparented to the original
+ * parent and these knotes re-fired.
+ */
+ if (event & NOTE_EXIT) {
+ if ((kn->kn_ptr.p_proc->p_oppid != 0)
+ && (kn->kn_kq->kq_p->p_pid != kn->kn_ptr.p_proc->p_ppid)) {
+ /*
+ * This knote is not for the current ptrace(2) parent, ignore.
+ */
+ return 0;
+ }
+ }
+
/*
* if the user is interested in this event, record it.
*/
void vproc_exit(proc_t p);
__private_extern__ void munge_user64_rusage(struct rusage *a_rusage_p, struct user64_rusage *a_user_rusage_p);
__private_extern__ void munge_user32_rusage(struct rusage *a_rusage_p, struct user32_rusage *a_user_rusage_p);
-static int reap_child_locked(proc_t parent, proc_t child, int deadparent, int locked, int droplock);
+static int reap_child_locked(proc_t parent, proc_t child, int deadparent, int reparentedtoinit, int locked, int droplock);
/*
* Things which should have prototypes in headers, but don't
/* wait till parentrefs are dropped and grant no more */
proc_childdrainstart(p);
while ((q = p->p_children.lh_first) != NULL) {
+ int reparentedtoinit = (q->p_listflag & P_LIST_DEADPARENT) ? 1 : 0;
q->p_listflag |= P_LIST_DEADPARENT;
if (q->p_stat == SZOMB) {
if (p != q->p_pptr)
* and the proc struct cannot be used for wakeups as well.
* It is safe to use q here as this is system reap
*/
- (void)reap_child_locked(p, q, 1, 1, 0);
+ (void)reap_child_locked(p, q, 1, reparentedtoinit, 1, 0);
} else {
proc_reparentlocked(q, initproc, 0, 1);
/*
set_bsdtask_info(task, NULL);
knote_hint = NOTE_EXIT | (p->p_xstat & 0xffff);
- if (p->p_oppid != 0) {
- knote_hint |= NOTE_EXIT_REPARENTED;
- }
-
proc_knote(p, knote_hint);
/* mark the thread as the one that is doing proc_exit
p->p_listflag |= P_LIST_DEADPARENT;
proc_list_unlock();
}
- if ((p->p_listflag & P_LIST_DEADPARENT) == 0) {
+ if ((p->p_listflag & P_LIST_DEADPARENT) == 0 || p->p_oppid) {
if (pp != initproc) {
proc_lock(pp);
pp->si_pid = p->p_pid;
* and the proc struct cannot be used for wakeups as well.
* It is safe to use p here as this is system reap
*/
- (void)reap_child_locked(pp, p, 1, 1, 1);
+ (void)reap_child_locked(pp, p, 1, 0, 1, 1);
/* list lock dropped by reap_child_locked */
}
if (uth->uu_lowpri_window) {
* 1 Process was reaped
*/
static int
-reap_child_locked(proc_t parent, proc_t child, int deadparent, int locked, int droplock)
+reap_child_locked(proc_t parent, proc_t child, int deadparent, int reparentedtoinit, int locked, int droplock)
{
proc_t trace_parent = PROC_NULL; /* Traced parent process, if tracing */
* ptraced can simply be reaped, refer to radar 5677288
* p_oppid -> ptraced
* trace_parent == initproc -> away from launchd
- * P_LIST_DEADPARENT -> came to launchd by reparenting
+ * reparentedtoinit -> came to launchd by reparenting
*/
- if (child->p_oppid && (trace_parent = proc_find(child->p_oppid))
- && !((trace_parent == initproc) && (child->p_lflag & P_LIST_DEADPARENT))) {
+ if (child->p_oppid) {
+ int knote_hint;
+ pid_t oppid;
+
proc_lock(child);
+ oppid = child->p_oppid;
child->p_oppid = 0;
+ knote_hint = NOTE_EXIT | (child->p_xstat & 0xffff);
proc_unlock(child);
- if (trace_parent != initproc) {
- /*
- * proc internal fileds and p_ucred usage safe
- * here as child is dead and is not reaped or
- * reparented yet
- */
- proc_lock(trace_parent);
- trace_parent->si_pid = child->p_pid;
- trace_parent->si_status = child->p_xstat;
- trace_parent->si_code = CLD_CONTINUED;
- trace_parent->si_uid = kauth_cred_getruid(child->p_ucred);
- proc_unlock(trace_parent);
- }
- proc_reparentlocked(child, trace_parent, 1, 0);
- psignal(trace_parent, SIGCHLD);
- proc_list_lock();
- wakeup((caddr_t)trace_parent);
- child->p_listflag &= ~P_LIST_WAITING;
- wakeup(&child->p_stat);
- proc_list_unlock();
- proc_rele(trace_parent);
- if ((locked == 1) && (droplock == 0))
+
+ if ((trace_parent = proc_find(oppid))
+ && !((trace_parent == initproc) && reparentedtoinit)) {
+
+ if (trace_parent != initproc) {
+ /*
+ * proc internal fileds and p_ucred usage safe
+ * here as child is dead and is not reaped or
+ * reparented yet
+ */
+ proc_lock(trace_parent);
+ trace_parent->si_pid = child->p_pid;
+ trace_parent->si_status = child->p_xstat;
+ trace_parent->si_code = CLD_CONTINUED;
+ trace_parent->si_uid = kauth_cred_getruid(child->p_ucred);
+ proc_unlock(trace_parent);
+ }
+ proc_reparentlocked(child, trace_parent, 1, 0);
+
+ /* resend knote to original parent (and others) after reparenting */
+ proc_knote(child, knote_hint);
+
+ psignal(trace_parent, SIGCHLD);
proc_list_lock();
- return (0);
- }
-
- if (trace_parent != PROC_NULL) {
- proc_rele(trace_parent);
+ wakeup((caddr_t)trace_parent);
+ child->p_listflag &= ~P_LIST_WAITING;
+ wakeup(&child->p_stat);
+ proc_list_unlock();
+ proc_rele(trace_parent);
+ if ((locked == 1) && (droplock == 0))
+ proc_list_lock();
+ return (0);
+ }
+
+ /*
+ * If we can't reparent (e.g. the original parent exited while child was being debugged, or
+ * original parent is the same as the debugger currently exiting), we still need to satisfy
+ * the knote lifecycle for other observers on the system. While the debugger was attached,
+ * the NOTE_EXIT would not have been broadcast during initial child termination.
+ */
+ proc_knote(child, knote_hint);
+
+ if (trace_parent != PROC_NULL) {
+ proc_rele(trace_parent);
+ }
}
proc_knote(child, NOTE_REAP);
if (p->p_stat == SZOMB) {
+ int reparentedtoinit = (p->p_listflag & P_LIST_DEADPARENT) ? 1 : 0;
+
proc_list_unlock();
#if CONFIG_MACF
if ((error = mac_proc_check_wait(q, p)) != 0)
}
/* Clean up */
- (void)reap_child_locked(q, p, 0, 0, 0);
+ (void)reap_child_locked(q, p, 0, reparentedtoinit, 0, 0);
return (0);
}
/* Prevent other process for waiting for this event? */
if (!(uap->options & WNOWAIT)) {
- (void) reap_child_locked(q, p, 0, 0, 0);
+ (void) reap_child_locked(q, p, 0, 0, 0, 0);
return (0);
}
goto out;
* and the proc struct cannot be used for wakeups as well.
* It is safe to use q here as this is system reap
*/
- (void)reap_child_locked(p, q, 1, 1, 0);
+ (void)reap_child_locked(p, q, 1, 0, 1, 0);
} else {
proc_reparentlocked(q, initproc, 0, 1);
/*
* and the proc struct cannot be used for wakeups as well.
* It is safe to use p here as this is system reap
*/
- (void)reap_child_locked(pp, p, 0, 1, 1);
+ (void)reap_child_locked(pp, p, 0, 0, 1, 1);
/* list lock dropped by reap_child_locked */
}
proc_rele(pp);
#include <kern/kalloc.h>
#include <kern/mach_param.h>
#include <kern/task.h>
+#include <kern/thread.h>
#include <kern/thread_call.h>
#include <kern/zalloc.h>
task_deallocate(child_task);
child_task = NULL;
}
+
+ /*
+ * Tag thread as being the first thread in its task.
+ */
+ thread_set_tag(child_thread, THREAD_TAG_MAINTHREAD);
+
bad:
thread_yield_internal(1);
CHECK_SET_VOID_HOOK(thread_label_init)
CHECK_SET_VOID_HOOK(thread_label_destroy)
.mpo_reserved18 = common_void_hook,
- .mpo_reserved19 = common_void_hook,
+ CHECK_SET_VOID_HOOK(vnode_notify_open)
.mpo_reserved20 = common_void_hook,
.mpo_reserved21 = common_void_hook,
.mpo_reserved22 = common_void_hook,
0x5040010 CQ_psema
0x5040014 CQ_plock
0x5040018 CG_action
+0x5070004 PM_SetParent
+0x5070008 PM_AddChild
+0x507000c PM_RemoveChild
+0x5070010 PM_CtrlDriver
+0x5070014 PM_CtrlDriverErr1
+0x5070018 PM_CtrlDriverErr2
+0x507001c PM_CtrlDriverErr3
+0x5070020 PM_CtrlDriverErr4
+0x5070024 PM_InterestDriver
+0x5070028 PM_InterestDriverAckErr1
+0x507002c PM_ChildAck
+0x5070030 PM_InterestDriverAck
+0x5070034 PM_InterestDriverAckErr2
+0x5070038 PM_InterestDriverAckErr3
+0x507003c PM_CtrlDriverAckErr4
+0x5070040 PM_CtrlDriverAck
+0x5070044 PM_DomainWillChange
+0x5070048 PM_DomainDidChange
+0x507004c PM_RequestDomainState
+0x5070050 PM_MakeUsable
+0x5070054 PM_ChangeStateTo
+0x5070058 PM_ChangeStateToPriv
+0x507005c PM_SetAggressiveness
+0x5070060 PM_CriticalTemp
+0x5070064 PM_OverrideOn
+0x5070068 PM_OverrideOff
+0x5070074 PM_ChangeDone
+0x5070078 PM_CtrlDriverTardy
+0x507007c PM_InterestDriverTardy
+0x5070080 PM_StartAckTimer
+0x5070084 PM_StartParentChange
+0x5070088 PM_AmendParentChange
+0x507008c PM_StartDeviceChange
+0x5070090 PM_RequestDenied
+0x5070094 PM_CtrlDriverErr5
+0x5070098 PM_ProgramHardware
+0x507009c PM_InformWillChange
+0x50700a0 PM_InformDidChange
+0x50700a4 PM_RemoveDriver
+0x50700a8 PM_SetIdleTimer
+0x50700ac PM_SystemWake
+0x50700b4 PM_ClientAck
+0x50700b8 PM_ClientTardy
+0x50700bc PM_ClientCancel
+0x50700c0 PM_ClientNotify
+0x50700c4 PM_AppNotify
+0x50700d4 PM_IdleCancel
+0x50700d8 PM_SystemTracePoint
0x5080004 IOSERVICE_BUSY
0x5080008 IOSERVICE_NONBUSY
0x508000c IOSERVICE_MODULESTALL
0x5080048 IOSERVICE_KEXTD_ALIVE
0x508004C IOSERVICE_KEXTD_READY
0x5080050 IOSERVICE_REGISTRY_QUIET
-0x5100004 PM_SetParent
-0x5100008 PM_AddChild
-0x510000c PM_RemoveChild
-0x5100010 PM_CtrlDriver
-0x5100014 PM_CtrlDrvrE1
-0x5100018 PM_CtrlDrvrE2
-0x510001c PM_CtrlDrvrE3
-0x5100020 PM_CtrlDrvrE4
-0x5100024 PM_IntDriver
-0x5100028 PM_AckE1
-0x510002c PM_ChildAck
-0x5100030 PM_DriverAck
-0x5100034 PM_AckE2
-0x5100038 PM_AckE3
-0x510003c PM_AckE4
-0x5100040 PM_DrvrAckSPwr
-0x5100044 PM_WillChange
-0x5100048 PM_DidChange
-0x510004c PM_ReqstDomain
-0x5100050 PM_MakeUsable
-0x5100054 PM_ChangeTo
-0x5100058 PM_ChngeToPriv
-0x510005c PM_SetAggrssvs
-0x5100060 PM_CritclTemp
-0x5100064 PM_OverrideOn
-0x5100068 PM_OverrideOff
-0x510006c PM_EnqueueErr
-0x5100070 PM_CollapseQ
-0x5100074 PM_ChangeDone
-0x5100078 PM_CtrlDrvTrdy
-0x510007c PM_IntDrvrTrdy
-0x5100080 PM_StartAckTmr
-0x5100084 PM_ParentChnge
-0x5100088 PM_AmndPrnChng
-0x510008c PM_DeviceChnge
-0x5100090 PM_ReqDenied
-0x5100094 PM_CtrlDrvrE45
-0x5100098 PM_PrgrmHrdwre
-0x510009c PM_InfDrvrPre
-0x51000a0 PM_InfDrvrPost
-0x51000a4 PM_RemoveDrivr
-0x51000a8 PM_IdlTimerPrd
-0x51000ac PM_SystemWake
-0x51000b0 PM_AckE5
-0x51000b4 PM_ClientAck
-0x51000b8 PM_ClientTardy
-0x51000bc PM_ClientCancl
-0x51000c0 PM_ClientNotfy
-0x51000c4 PM_AppNotify
0x5230000 HID_Unexpected
0x5230004 HID_KeyboardLEDThreadTrigger
0x5230008 HID_KeyboardLEDThreadActive
/*
- * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2013 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
vlan_lock();
goto signal_done;
}
- /* mark the parent interface up */
- ifnet_set_flags(p, IFF_UP, IFF_UP);
- (void)ifnet_ioctl(p, 0, SIOCSIFFLAGS, (caddr_t)NULL);
}
/* configure parent to receive our multicast addresses */
if (ifv != NULL) {
ifvlan_release(ifv);
}
+ if (first_vlan) {
+ /* mark the parent interface up */
+ ifnet_set_flags(p, IFF_UP, IFF_UP);
+ (void)ifnet_ioctl(p, 0, SIOCSIFFLAGS, (caddr_t)NULL);
+ }
return 0;
signal_done:
int asd = 0;
int match = 0;
u_int8_t icmptype = 0, icmpcode = 0;
- union pf_state_xport nxport, sxport, dxport;
struct ip_fw_args dnflow;
struct pf_rule *prev_matching_rule = fwa ? fwa->fwa_pf_rule : NULL;
int found_prev_rule = (prev_matching_rule) ? 0 : 1;
if (!DUMMYNET_LOADED)
return (PF_PASS);
- if (TAILQ_EMPTY(pf_main_ruleset.rules[PF_RULESET_DUMMYNET].active.ptr)) {
+ if (TAILQ_EMPTY(pf_main_ruleset.rules[PF_RULESET_DUMMYNET].active.ptr))
return (PF_PASS);
- }
+
bzero(&dnflow, sizeof(dnflow));
hdrlen = 0;
- sxport.spi = 0;
- dxport.spi = 0;
- nxport.spi = 0;
/* Fragments don't gave protocol headers */
if (!(pd->flags & PFDESC_IP_FRAG))
switch (pd->proto) {
case IPPROTO_TCP:
dnflow.fwa_id.flags = pd->hdr.tcp->th_flags;
- dnflow.fwa_id.dst_port = pd->hdr.tcp->th_dport;
- dnflow.fwa_id.src_port = pd->hdr.tcp->th_sport;
- sxport.port = pd->hdr.tcp->th_sport;
- dxport.port = pd->hdr.tcp->th_dport;
+ dnflow.fwa_id.dst_port = ntohs(pd->hdr.tcp->th_dport);
+ dnflow.fwa_id.src_port = ntohs(pd->hdr.tcp->th_sport);
hdrlen = sizeof (*th);
break;
case IPPROTO_UDP:
- dnflow.fwa_id.dst_port = pd->hdr.udp->uh_dport;
- dnflow.fwa_id.src_port = pd->hdr.udp->uh_sport;
- sxport.port = pd->hdr.udp->uh_sport;
- dxport.port = pd->hdr.udp->uh_dport;
+ dnflow.fwa_id.dst_port = ntohs(pd->hdr.udp->uh_dport);
+ dnflow.fwa_id.src_port = ntohs(pd->hdr.udp->uh_sport);
hdrlen = sizeof (*pd->hdr.udp);
break;
#if INET
case IPPROTO_ICMP:
- if (pd->af != AF_INET)
+ if (af != AF_INET)
break;
- sxport.port = dxport.port = pd->hdr.icmp->icmp_id;
hdrlen = ICMP_MINLEN;
icmptype = pd->hdr.icmp->icmp_type;
icmpcode = pd->hdr.icmp->icmp_code;
#endif /* INET */
#if INET6
case IPPROTO_ICMPV6:
- if (pd->af != AF_INET6)
+ if (af != AF_INET6)
break;
- sxport.port = dxport.port = pd->hdr.icmp6->icmp6_id;
hdrlen = sizeof (*pd->hdr.icmp6);
icmptype = pd->hdr.icmp6->icmp6_type;
icmpcode = pd->hdr.icmp6->icmp6_code;
break;
#endif /* INET6 */
case IPPROTO_GRE:
- if (pd->proto_variant == PF_GRE_PPTP_VARIANT) {
- sxport.call_id = dxport.call_id =
- pd->hdr.grev1->call_id;
+ if (pd->proto_variant == PF_GRE_PPTP_VARIANT)
hdrlen = sizeof (*pd->hdr.grev1);
- }
break;
case IPPROTO_ESP:
- sxport.spi = 0;
- dxport.spi = pd->hdr.esp->spi;
hdrlen = sizeof (*pd->hdr.esp);
break;
}
dnflow.fwa_cookie = r->dnpipe;
dnflow.fwa_pf_rule = r;
- dnflow.fwa_id.addr_type = (af == AF_INET) ? 4 : 6;
dnflow.fwa_id.proto = pd->proto;
dnflow.fwa_flags = r->dntype;
-
+ switch (af) {
+ case AF_INET:
+ dnflow.fwa_id.addr_type = 4;
+ dnflow.fwa_id.src_ip = ntohl(saddr->v4.s_addr);
+ dnflow.fwa_id.dst_ip = ntohl(daddr->v4.s_addr);
+ break;
+ case AF_INET6:
+ dnflow.fwa_id.addr_type = 6;
+ dnflow.fwa_id.src_ip6 = saddr->v6;
+ dnflow.fwa_id.dst_ip6 = saddr->v6;
+ break;
+ }
+
if (fwa != NULL) {
dnflow.fwa_oif = fwa->fwa_oif;
dnflow.fwa_oflags = fwa->fwa_oflags;
* max_allowed_cwnd = allowed_increase + (tether * flight_size)
* cwnd = min(cwnd, max_allowed_cwnd)
*
- * 'Allowed_increase' parameter is set to 2. If the flight size is zero, then
- * we want the congestion window to be at least 2 packets to reduce the
- * delay induced by delayed ack. This helps when the receiver is acking every
- * other packet.
+ * 'Allowed_increase' parameter is set to 8. If the flight size is zero, then
+ * we want the congestion window to be at least 8 packets to reduce the
+ * delay induced by delayed ack. This helps when the receiver is acking
+ * more than 2 packets at a time (stretching acks for better performance).
*
* 'Tether' is also set to 2. We do not want this to limit the growth of cwnd
* during slow-start.
*/
-int allowed_increase = 2;
+int allowed_increase = 8;
SYSCTL_INT(_net_inet_tcp, OID_AUTO, bg_allowed_increase, CTLFLAG_RW | CTLFLAG_LOCKED,
&allowed_increase, 1, "Additive constant used to calculate max allowed congestion window");
/*
- * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/proc.h>
#include <sys/kauth.h>
#include <sys/mount_internal.h>
+#include <sys/vnode_internal.h>
#include <sys/vnode.h>
#include <sys/ubc.h>
#include <sys/malloc.h>
return (fhsum);
}
+
+int nfs_case_insensitive(mount_t);
+
+int
+nfs_case_insensitive(mount_t mp)
+{
+ struct nfsmount *nmp = VFSTONFS(mp);
+ int answer = 0;
+ int skip = 0;
+
+ if (nmp == NULL) {
+ return (0);
+ }
+
+ if (nmp->nm_vers == NFS_VER2) {
+ /* V2 has no way to know */
+ return (0);
+ }
+
+ lck_mtx_lock(&nmp->nm_lock);
+ if (nmp->nm_vers == NFS_VER3) {
+ if (!(nmp->nm_state & NFSSTA_GOTPATHCONF)) {
+ /* We're holding the node lock so we just return
+ * with answer as case sensitive. Is very rare
+ * for file systems not to be homogenous w.r.t. pathconf
+ */
+ skip = 1;
+ }
+ } else if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) {
+ /* no pathconf info cached */
+ skip = 1;
+ }
+
+ if (!skip && NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CASE_INSENSITIVE))
+ answer = 1;
+
+ lck_mtx_unlock(&nmp->nm_lock);
+
+ return (answer);
+}
+
+
/*
* Look up a vnode/nfsnode by file handle.
* Callers must check for mount points!!
} else {
if (dnp && cnp && (flags & NG_MAKEENTRY))
cache_enter(NFSTOV(dnp), vp, cnp);
+ /*
+ * Update the vnode if the name/and or the parent has
+ * changed. We need to do this so that if getattrlist is
+ * called asking for ATTR_CMN_NAME, that the "most"
+ * correct name is being returned if we're not making an
+ * entry. In addition for monitored vnodes we need to
+ * kick the vnode out of the name cache. We do this so
+ * that if there are hard links in the same directory
+ * the link will not be found and a lookup will get us
+ * here to return the name of the current link. In
+ * addition by removing the name from the name cache the
+ * old name will not be found after a rename done on
+ * another client or the server. The principle reason
+ * to do this is because Finder is asking for
+ * notifications on a directory. The directory changes,
+ * Finder gets notified, reads the directory (which we
+ * have purged) and for each entry returned calls
+ * getattrlist with the name returned from
+ * readdir. gettattrlist has to call namei/lookup to
+ * resolve the name, because its not in the cache we end
+ * up here. We need to update the name so Finder will
+ * get the name it called us with.
+ *
+ * We had an imperfect solution with respect to case
+ * sensitivity. There is a test that is run in
+ * FileBuster that does renames from some name to
+ * another name differing only in case. It then reads
+ * the directory looking for the new name, after it
+ * finds that new name, it ask gettattrlist to verify
+ * that the name is the new name. Usually that works,
+ * but renames generate fsevents and fseventsd will do a
+ * lookup on the name via lstat. Since that test renames
+ * old name to new name back and forth there is a race
+ * that an fsevent will be behind and will access the
+ * file by the old name, on a case insensitive file
+ * system that will work. Problem is if we do a case
+ * sensitive compare, we're going to change the name,
+ * which the test's getattrlist verification step is
+ * going to fail. So we will check the case sensitivity
+ * of the file system and do the appropriate compare. In
+ * a rare instance for non homogeneous file systems
+ * w.r.t. pathconf we will use case sensitive compares.
+ * That could break if the file system is actually case
+ * insensitive.
+ *
+ * Note that V2 does not know the case, so we just
+ * assume case sensitivity.
+ *
+ * This is clearly not perfect due to races, but this is
+ * as good as its going to get. You can defeat the
+ * handling of hard links simply by doing:
+ *
+ * while :; do ls -l > /dev/null; done
+ *
+ * in a terminal window. Even a single ls -l can cause a
+ * race.
+ *
+ * <rant>What we really need is for the caller, that
+ * knows the name being used is valid since it got it
+ * from a readdir to use that name and not ask for the
+ * ATTR_CMN_NAME</rant>
+ */
+ if (dnp && cnp && (vp != NFSTOV(dnp))) {
+ int update_flags = vnode_ismonitored((NFSTOV(dnp))) ? VNODE_UPDATE_CACHE : 0;
+ int (*cmp)(const char *s1, const char *s2, size_t n);
+
+ cmp = nfs_case_insensitive(mp) ? strncasecmp : strncmp;
+
+ if (vp->v_name && cnp->cn_namelen && (*cmp)(cnp->cn_nameptr, vp->v_name, cnp->cn_namelen))
+ update_flags |= VNODE_UPDATE_NAME;
+ if ((vp->v_name == NULL && cnp->cn_namelen != 0) || (vp->v_name != NULL && cnp->cn_namelen == 0))
+ update_flags |= VNODE_UPDATE_NAME;
+ if (vnode_parent(vp) != NFSTOV(dnp))
+ update_flags |= VNODE_UPDATE_PARENT;
+ if (update_flags)
+ vnode_update_identity(vp, NFSTOV(dnp), cnp->cn_nameptr, cnp->cn_namelen, 0, update_flags);
+ }
+
*npp = np;
}
FSDBG_BOT(263, dnp, *npp, 0xcace0000, error);
#define CP_READ_ACCESS 0x1
#define CP_WRITE_ACCESS 0x2
-/*
- * Check for this version when deciding to enable features
- */
#define CONTENT_PROTECTION_XATTR_NAME "com.apple.system.cprotect"
#define CP_NEW_MAJOR_VERS 4
#define CP_PREV_MAJOR_VERS 2
errno_t vnode_removenamedstream(vnode_t, vnode_t, const char *, int, vfs_context_t);
errno_t vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context);
errno_t vnode_relenamedstream(vnode_t vp, vnode_t svp, vfs_context_t context);
+errno_t vnode_verifynamedstream (vnode_t vp, vfs_context_t ctx);
#endif
}
ndp->ni_flag &= ~(NAMEI_TRAILINGSLASH);
}
-
+
+#if NAMEDSTREAMS
+ /*
+ * Deny namei/lookup requests to resolve paths that point to shadow files.
+ * Access to shadow files must be conducted by explicit calls to VNOP_LOOKUP
+ * directly, and not use lookup/namei
+ */
+ if (vnode_isshadow (dp)) {
+ error = ENOENT;
+ goto out;
+ }
+#endif
+
nextname:
/*
* Not a symbolic link. If more pathname,
action |= KAUTH_VNODE_WRITE_DATA;
}
}
- return (vnode_authorize(vp, NULL, action, ctx));
+ error = vnode_authorize(vp, NULL, action, ctx);
+
+#if NAMEDSTREAMS
+ if (error == EACCES) {
+ /*
+ * Shadow files may exist on-disk with a different UID/GID
+ * than that of the current context. Verify that this file
+ * is really a shadow file. If it was created successfully
+ * then it should be authorized.
+ */
+ if (vnode_isshadow(vp) && vnode_isnamedstream (vp)) {
+ error = vnode_verifynamedstream(vp, ctx);
+ }
+ }
+#endif
+
+ return error;
}
int
return error;
}
- /* call out to allow 3rd party notification of open.
+ /* Call out to allow 3rd party notification of open.
* Ignore result of kauth_authorize_fileop call.
*/
+#if CONFIG_MACF
+ mac_vnode_notify_open(ctx, vp, fmode);
+#endif
kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN,
(uintptr_t)vp, 0);
goto bad;
}
- /* call out to allow 3rd party notification of open.
+ /* Call out to allow 3rd party notification of open.
* Ignore result of kauth_authorize_fileop call.
*/
+#if CONFIG_MACF
+ mac_vnode_notify_open(ctx, vp, fmode);
+#endif
kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN,
(uintptr_t)vp, 0);
return (error);
}
+/*
+ * Verify that the vnode 'vp' is a vnode that lives in the shadow
+ * directory. We can't just query the parent pointer directly since
+ * the shadowfile is hooked up to the actual file it's a stream for.
+ */
+errno_t vnode_verifynamedstream(vnode_t vp, vfs_context_t context) {
+ int error;
+ struct vnode *shadow_dvp = NULL;
+ struct vnode *shadowfile = NULL;
+ struct componentname cn;
+ char tmpname[80];
+
+
+ /* Get the shadow directory vnode */
+ error = get_shadow_dir(&shadow_dvp, context);
+ if (error) {
+ return error;
+ }
+
+ /* Re-generate the shadow name in the buffer */
+ MAKE_SHADOW_NAME (vp, tmpname);
+
+ /* Look up item in shadow dir */
+ bzero(&cn, sizeof(cn));
+ cn.cn_nameiop = LOOKUP;
+ cn.cn_flags = ISLASTCN | CN_ALLOWRSRCFORK;
+ cn.cn_context = context;
+ cn.cn_pnbuf = tmpname;
+ cn.cn_pnlen = sizeof(tmpname);
+ cn.cn_nameptr = cn.cn_pnbuf;
+ cn.cn_namelen = strlen(tmpname);
+
+ if (VNOP_LOOKUP (shadow_dvp, &shadowfile, &cn, context) == 0) {
+ /* is the pointer the same? */
+ if (shadowfile == vp) {
+ error = 0;
+ }
+ else {
+ error = EPERM;
+ }
+ /* drop the iocount acquired */
+ vnode_put (shadowfile);
+ }
+
+ /* Drop iocount on shadow dir */
+ vnode_put (shadow_dvp);
+ return error;
+}
static int
getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
-12.3.0
+12.4.0
# The first line of this file contains the master version number for the kernel.
# All other instances of the kernel version in xnu are derived from this file.
protected:
bool tellClientsWithResponse( int messageType );
void tellClients( int messageType );
+ void PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 );
private:
#ifndef __LP64__
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
enum PMLogEnum {
- kPMLogSetParent = 1, // 1 0x05100004
- kPMLogAddChild, // 2 0x05100008
- kPMLogRemoveChild, // 3 0x0510000c
- kPMLogControllingDriver, // 4 0x05100010
- kPMLogControllingDriverErr1, // 5 0x05100014 - bad power state array version
- kPMLogControllingDriverErr2, // 6 0x05100018 - power states already registered
- kPMLogControllingDriverErr3, // 7 0x0510001c
- kPMLogControllingDriverErr4, // 8 0x05100020 - power driver is invalid
- kPMLogInterestedDriver, // 9 0x05100024
- kPMLogAcknowledgeErr1, // 10 0x05100028 - unknown entity called acknowledgePowerChange
- kPMLogChildAcknowledge, // 11 0x0510002c
- kPMLogDriverAcknowledge, // 12 0x05100030 - interested driver acknowledges
- kPMLogAcknowledgeErr2, // 13 0x05100034 - object has already acked
- kPMLogAcknowledgeErr3, // 14 0x05100038 - not expecting any acks
- kPMLogAcknowledgeErr4, // 15 0x0510003c - not expecting acknowledgeSetPowerState
- kPMLogDriverAcknowledgeSet, // 16 0x05100040 - controlling driver acknowledges
- kPMLogWillChange, // 17 0x05100044
- kPMLogDidChange, // 18 0x05100048
- kPMLogRequestDomain, // 19 0x0510004c
- kPMLogMakeUsable, // 20 0x05100050
- kPMLogChangeStateTo, // 21 0x05100054
- kPMLogChangeStateToPriv, // 22 0x05100058
- kPMLogSetAggressiveness, // 23 0x0510005c
- kPMLogCriticalTemp, // 24 0x05100060
- kPMLogOverrideOn, // 25 0x05100064
- kPMLogOverrideOff, // 26 0x05100068
- kPMLogEnqueueErr, // 27 0x0510006c - NOT USED
- kPMLogCollapseQueue, // 28 0x05100070 - NOT USED
- kPMLogChangeDone, // 29 0x05100074
- kPMLogCtrlDriverTardy, // 30 0x05100078 - controlling driver didn't acknowledge
- kPMLogIntDriverTardy, // 31 0x0510007c - interested driver didn't acknowledge
- kPMLogStartAckTimer, // 32 0x05100080
- kPMLogStartParentChange, // 33 0x05100084
- kPMLogAmendParentChange, // 34 0x05100088
- kPMLogStartDeviceChange, // 35 0x0510008c
- kPMLogRequestDenied, // 36 0x05100090 - parent denied domain state change request
- kPMLogControllingDriverErr5, // 37 0x05100094 - too few power states
- kPMLogProgramHardware, // 38 0x05100098
- kPMLogInformDriverPreChange, // 39 0x0510009c
- kPMLogInformDriverPostChange, // 40 0x051000a0
- kPMLogRemoveDriver, // 41 0x051000a4 - NOT USED
- kPMLogSetIdleTimerPeriod, // 42 0x051000a8
- kPMLogSystemWake, // 43 0x051000ac
- kPMLogAcknowledgeErr5, // 44 0x051000b0
- kPMLogClientAcknowledge, // 45 0x051000b4
- kPMLogClientTardy, // 46 0x051000b8 - application didn't acknowledge
- kPMLogClientCancel, // 47 0x051000bc - NOT USED
- kPMLogClientNotify, // 48 0x051000c0 - client sent a notification
- kPMLogAppNotify, // 49 0x051000c4 - application sent a notification
- kPMLogSetClockGating, // 50 0x051000c8 - NOT USED
- kPMLogSetPowerGating, // 51 0x051000cc - NOT USED
- kPMLogSetPinGroup, // 52 0x051000d0 - NOT USED
- kPMLogIdleCancel, // 53 0x051000d4 - device unidle during change
+ kPMLogSetParent = 1, // 1 0x05070004
+ kPMLogAddChild, // 2 0x05070008
+ kPMLogRemoveChild, // 3 0x0507000c
+ kPMLogControllingDriver, // 4 0x05070010
+ kPMLogControllingDriverErr1, // 5 0x05070014 - bad power state array version
+ kPMLogControllingDriverErr2, // 6 0x05070018 - power states already registered
+ kPMLogControllingDriverErr3, // 7 0x0507001c
+ kPMLogControllingDriverErr4, // 8 0x05070020 - power driver is invalid
+ kPMLogInterestedDriver, // 9 0x05070024
+ kPMLogAcknowledgeErr1, // 10 0x05070028 - unknown entity called acknowledgePowerChange
+ kPMLogChildAcknowledge, // 11 0x0507002c
+ kPMLogDriverAcknowledge, // 12 0x05070030 - interested driver acknowledges
+ kPMLogAcknowledgeErr2, // 13 0x05070034 - object has already acked
+ kPMLogAcknowledgeErr3, // 14 0x05070038 - not expecting any acks
+ kPMLogAcknowledgeErr4, // 15 0x0507003c - not expecting acknowledgeSetPowerState
+ kPMLogDriverAcknowledgeSet, // 16 0x05070040 - controlling driver acknowledges
+ kPMLogWillChange, // 17 0x05070044
+ kPMLogDidChange, // 18 0x05070048
+ kPMLogRequestDomain, // 19 0x0507004c
+ kPMLogMakeUsable, // 20 0x05070050
+ kPMLogChangeStateTo, // 21 0x05070054
+ kPMLogChangeStateToPriv, // 22 0x05070058
+ kPMLogSetAggressiveness, // 23 0x0507005c
+ kPMLogCriticalTemp, // 24 0x05070060
+ kPMLogOverrideOn, // 25 0x05070064
+ kPMLogOverrideOff, // 26 0x05070068
+ kPMLogEnqueueErr, // 27 0x0507006c - NOT USED
+ kPMLogCollapseQueue, // 28 0x05070070 - NOT USED
+ kPMLogChangeDone, // 29 0x05070074
+ kPMLogCtrlDriverTardy, // 30 0x05070078 - controlling driver didn't acknowledge
+ kPMLogIntDriverTardy, // 31 0x0507007c - interested driver didn't acknowledge
+ kPMLogStartAckTimer, // 32 0x05070080
+ kPMLogStartParentChange, // 33 0x05070084
+ kPMLogAmendParentChange, // 34 0x05070088
+ kPMLogStartDeviceChange, // 35 0x0507008c
+ kPMLogRequestDenied, // 36 0x05070090 - parent denied domain state change request
+ kPMLogControllingDriverErr5, // 37 0x05070094 - too few power states
+ kPMLogProgramHardware, // 38 0x05070098
+ kPMLogInformDriverPreChange, // 39 0x0507009c
+ kPMLogInformDriverPostChange, // 40 0x050700a0
+ kPMLogRemoveDriver, // 41 0x050700a4 - NOT USED
+ kPMLogSetIdleTimerPeriod, // 42 0x050700a8
+ kPMLogSystemWake, // 43 0x050700ac
+ kPMLogAcknowledgeErr5, // 44 0x050700b0
+ kPMLogClientAcknowledge, // 45 0x050700b4
+ kPMLogClientTardy, // 46 0x050700b8 - application didn't acknowledge
+ kPMLogClientCancel, // 47 0x050700bc - NOT USED
+ kPMLogClientNotify, // 48 0x050700c0 - client sent a notification
+ kPMLogAppNotify, // 49 0x050700c4 - application sent a notification
+ kPMLogSetClockGating, // 50 0x050700c8 - NOT USED
+ kPMLogSetPowerGating, // 51 0x050700cc - NOT USED
+ kPMLogSetPinGroup, // 52 0x050700d0 - NOT USED
+ kPMLogIdleCancel, // 53 0x050700d4 - device unidle during change
+ kPMLogSleepWakeTracePoint, // 54 0x050700d8 - kIOPMTracePoint markers
kIOPMlogLastEvent
};
#endif
// log system wake
- getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
+ PMDebug(kPMLogSystemWake, 0, 0);
lowBatteryCondition = false;
lastSleepReason = 0;
{
if (systemBooting) return;
+ PMDebug(kPMLogSleepWakeTracePoint, point, 0);
pmTracer->tracePoint(point);
#if HIBERNATION
void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
{
- if (!systemBooting)
- pmTracer->tracePoint(point, data);
+ if (systemBooting) return;
+
+ PMDebug(kPMLogSleepWakeTracePoint, point, data);
+ pmTracer->tracePoint(point, data);
}
void IOPMrootDomain::traceDetail( uint32_t detail )
PMLog(const char *who, unsigned long event,
unsigned long param1, unsigned long param2)
{
- UInt32 debugFlags = gIOKitDebug;
- UInt32 traceFlags = gIOKitTrace;
- uintptr_t name = 0;
- UInt32 i = 0;
-
- if (debugFlags & kIOLogPower) {
-
clock_sec_t nows;
clock_usec_t nowus;
clock_get_system_microtime(&nows, &nowus);
nowus += (nows % 1000) * 1000000;
- kprintf("pm%u %p %.30s %d %lx %lx\n",
+ kprintf("pm%u %p %.30s %d %lx %lx\n",
nowus, current_thread(), who, // Identity
(int) event, (long) param1, (long) param2); // Args
-
- if (traceFlags & kIOTracePowerMgmt) {
- static const UInt32 sStartStopBitField[] =
- { 0x00000000, 0x00000040 }; // Only Program Hardware so far
-
- // Arcane formula from Hacker's Delight by Warren
- // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
- UInt32 sgnevent = ((long) event >> 31);
- UInt32 absevent = sgnevent ^ (event + sgnevent);
- UInt32 code = IODBG_POWER(absevent);
-
- UInt32 bit = 1 << (absevent & 0x1f);
- if (absevent < sizeof(sStartStopBitField) * 8
- && (sStartStopBitField[absevent >> 5] & bit) ) {
- // Or in the START or END bits, Start = 1 & END = 2
- // If sgnevent == 0 then START - 0 => START
- // else if sgnevent == -1 then START - -1 => END
- code |= DBG_FUNC_START - sgnevent;
- }
-
- // Get first 8 characters of the name
- while ( i < sizeof(uintptr_t) && who[i] != 0)
- { ((char *)&name)[sizeof(uintptr_t)-i-1]=who[i]; i++; }
- // Record the timestamp.
- IOTimeStampConstant(code, name, event, param1, param2);
- }
- }
}
#include <IOKit/IOEventSource.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOCommand.h>
+#include <IOKit/IOTimeStamp.h>
#include <IOKit/pwr_mgt/IOPMlog.h>
#include <IOKit/pwr_mgt/IOPMinformee.h>
#define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
#define kPwrMgtKey "IOPowerManagement"
-#define OUR_PMLog(t, a, b) \
- do { gPlatform->PMLog( fName, t, a, b); } while(0)
+#define OUR_PMLog(t, a, b) do { \
+ if (gIOKitDebug & kIOLogPower) \
+ pwrMgt->pmPrint(t, a, b); \
+ if (gIOKitTrace & kIOTracePowerMgmt) \
+ pwrMgt->pmTrace(t, a, b); \
+ } while(0)
#define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
#define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
}
}
+void IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
+{
+ OUR_PMLog(event, param1, param2);
+}
+
//*********************************************************************************
// [public] joinPMtree
//
#if PM_VARS_SUPPORT
fPMVars->myCurrentState = fCurrentPowerState;
#endif
- OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
+ OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
PM_ACTION_2(actionPowerChangeDone,
fHeadNotePowerState, fHeadNoteChangeFlags);
callAction = true;
#endif
fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainFlags);
- OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
+ OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
PM_ACTION_2(actionPowerChangeDone,
fHeadNotePowerState, fHeadNoteChangeFlags);
callAction = true;
return (kIOReturnSuccess == ret);
}
+void IOServicePM::pmPrint(
+ uint32_t event,
+ uintptr_t param1,
+ uintptr_t param2 ) const
+{
+ gPlatform->PMLog(Name, event, param1, param2);
+}
+
+void IOServicePM::pmTrace(
+ uint32_t event,
+ uintptr_t param1,
+ uintptr_t param2 ) const
+{
+ const char * who = Name;
+ uint64_t regId = Owner->getRegistryEntryID();
+ uintptr_t name = 0;
+
+ static const uint32_t sStartStopBitField[] =
+ { 0x00000000, 0x00000040 }; // Only Program Hardware so far
+
+ // Arcane formula from Hacker's Delight by Warren
+ // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
+ uint32_t sgnevent = ((int) event >> 31);
+ uint32_t absevent = sgnevent ^ (event + sgnevent);
+ uint32_t code = IODBG_POWER(absevent);
+
+ uint32_t bit = 1 << (absevent & 0x1f);
+ if ((absevent < (sizeof(sStartStopBitField) * 8)) &&
+ (sStartStopBitField[absevent >> 5] & bit))
+ {
+ // Or in the START or END bits, Start = 1 & END = 2
+ // If sgnevent == 0 then START - 0 => START
+ // else if sgnevent == -1 then START - -1 => END
+ code |= DBG_FUNC_START - sgnevent;
+ }
+
+ // Copy the first characters of the name into an uintptr_t
+ for (uint32_t i = 0; (i < sizeof(uintptr_t) && who[i] != 0); i++)
+ {
+ ((char *) &name)[sizeof(uintptr_t) - i - 1] = who[i];
+ }
+
+ IOTimeStampConstant(code, name, (uintptr_t) regId, param1, param2);
+}
+
PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
const char *ownerName,
uintptr_t ownerUnique,
// Serialize IOServicePM state for debug output.
IOReturn gatedSerialize( OSSerialize * s );
virtual bool serialize( OSSerialize * s ) const;
+
+ // PM log and trace
+ void pmPrint( uint32_t event, uintptr_t param1, uintptr_t param2 ) const;
+ void pmTrace( uint32_t event, uintptr_t param1, uintptr_t param2 ) const;
};
#define fOwner pwrMgt->Owner
#include <IOKit/IOTimeStamp.h>
#include <IOKit/IOKitDebug.h>
+#if CONFIG_DTRACE
+#include <mach/sdt.h>
+#endif
+
#define super IOEventSource
OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource)
OSMetaClassDefineReservedUnused(IOTimerEventSource, 0);
(uintptr_t) doit, (uintptr_t) me->owner);
(*doit)(me->owner, me);
+#if CONFIG_DTRACE
+ DTRACE_TMR3(iotescallout__expire, Action, doit, OSObject, me->owner, void, me->workLoop);
+#endif
if (trace)
IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
(uintptr_t) doit, (uintptr_t) me->owner);
(*doit)(me->owner, me);
+#if CONFIG_DTRACE
+ DTRACE_TMR3(iotescallout__expire, Action, doit, OSObject, me->owner, void, me->workLoop);
+#endif
if (trace)
IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
#include <IOKit/IOTimeStamp.h>
#include <IOKit/IOKitDebug.h>
#include <libkern/OSDebug.h>
+#include <kern/thread.h>
#define super OSObject
return false;
}
+ (void) thread_set_tag(workThread, THREAD_TAG_IOWORKLOOP);
return true;
}
/* port unlocked */
if ( notify != IP_NULL)
ipc_port_release_sonce(notify);
+ } else {
+ ip_unlock(port);
}
}
iokit_remove_reference( obj );
diagWork dgWork;
uint64_t lastRuptClear = 0ULL;
+void cpu_powerstats(void *);
+
+typedef struct {
+ uint64_t caperf;
+ uint64_t cmperf;
+ uint64_t ccres[3];
+ uint64_t crtimes[4];
+ uint64_t citimes[4];
+ uint64_t crtime_total;
+ uint64_t citime_total;
+} core_energy_stat_t;
+
+typedef struct {
+ uint64_t pkg_cres[2][4];
+ uint64_t pkg_power_unit;
+ uint64_t pkg_energy;
+ uint32_t ncpus;
+ core_energy_stat_t cest[];
+} pkg_energy_statistics_t;
+
int
diagCall64(x86_saved_state_t * state)
uint64_t currNap, durNap;
x86_saved_state64_t *regs;
boolean_t diagflag;
+ uint32_t rval = 0;
assert(is_saved_state64(state));
regs = saved_state64(state);
switch (selector) { /* Select the routine */
case dgRuptStat: /* Suck Interruption statistics */
(void) ml_set_interrupts_enabled(TRUE);
- if (diagflag == 0)
- break;
data = regs->rsi; /* Get the number of processors */
if (data == 0) { /* If no location is specified for data, clear all
}
lastRuptClear = mach_absolute_time(); /* Get the time of clear */
- return 1; /* Normal return */
+ rval = 1; /* Normal return */
+ break;
}
(void) copyout((char *) &real_ncpus, data, sizeof(real_ncpus)); /* Copy out number of
curpos = curpos + (256 * sizeof(uint32_t) + 8); /* Point to next out put
* slot */
}
- return 1;
+ rval = 1;
break;
+ case dgPowerStat:
+ {
+ uint32_t c2l = 0, c2h = 0, c3l = 0, c3h = 0, c6l = 0, c6h = 0, c7l = 0, c7h = 0;
+ uint32_t pkg_unit_l = 0, pkg_unit_h = 0, pkg_ecl = 0, pkg_ech = 0;
+
+ pkg_energy_statistics_t pkes;
+ core_energy_stat_t cest;
+
+ bzero(&pkes, sizeof(pkes));
+ bzero(&cest, sizeof(cest));
+
+ rdmsr_carefully(MSR_IA32_PKG_C2_RESIDENCY, &c2l, &c2h);
+ rdmsr_carefully(MSR_IA32_PKG_C3_RESIDENCY, &c3l, &c3h);
+ rdmsr_carefully(MSR_IA32_PKG_C6_RESIDENCY, &c6l, &c6h);
+ rdmsr_carefully(MSR_IA32_PKG_C7_RESIDENCY, &c7l, &c7h);
+
+ pkes.pkg_cres[0][0] = ((uint64_t)c2h << 32) | c2l;
+ pkes.pkg_cres[0][1] = ((uint64_t)c3h << 32) | c3l;
+ pkes.pkg_cres[0][2] = ((uint64_t)c6h << 32) | c6l;
+ pkes.pkg_cres[0][3] = ((uint64_t)c7h << 32) | c7l;
+
+ rdmsr_carefully(MSR_IA32_PKG_POWER_SKU_UNIT, &pkg_unit_l, &pkg_unit_h);
+ rdmsr_carefully(MSR_IA32_PKG_ENERGY_STATUS, &pkg_ecl, &pkg_ech);
+
+ pkes.pkg_power_unit = ((uint64_t)pkg_unit_h << 32) | pkg_unit_l;
+ pkes.pkg_energy = ((uint64_t)pkg_ech << 32) | pkg_ecl;
+
+ pkes.ncpus = real_ncpus;
+
+ (void) ml_set_interrupts_enabled(TRUE);
+
+ copyout(&pkes, regs->rsi, sizeof(pkes));
+ curpos = regs->rsi + sizeof(pkes);
+
+ mp_cpus_call(CPUMASK_ALL, ASYNC, cpu_powerstats, NULL);
+
+ for (i = 0; i < real_ncpus; i++) {
+ cest.caperf = cpu_data_ptr[i]->cpu_aperf;
+ cest.cmperf = cpu_data_ptr[i]->cpu_mperf;
+ cest.ccres[0] = cpu_data_ptr[i]->cpu_c3res;
+ cest.ccres[1] = cpu_data_ptr[i]->cpu_c6res;
+ cest.ccres[2] = cpu_data_ptr[i]->cpu_c7res;
+
+ bcopy(&cpu_data_ptr[i]->cpu_rtimes[0], &cest.crtimes[0], sizeof(cest.crtimes));
+ bcopy(&cpu_data_ptr[i]->cpu_itimes[0], &cest.citimes[0], sizeof(cest.citimes));
+ cest.citime_total = cpu_data_ptr[i]->cpu_itime_total;
+ cest.crtime_total = cpu_data_ptr[i]->cpu_rtime_total;
+
+ copyout(&cest, curpos, sizeof(cest));
+ curpos += sizeof(cest);
+ }
+ rval = 1;
+ }
+ break;
+
#if DEBUG
case dgGzallocTest:
{
if (diagflag == 0)
break;
- return pmap_permissions_verify(kernel_pmap, kernel_map, 0, ~0ULL);
+ rval = pmap_permissions_verify(kernel_pmap, kernel_map, 0, ~0ULL);
}
break;
#endif /* __x86_64__*/
default: /* Handle invalid ones */
- return 0; /* Return an exception */
+ rval = 0; /* Return an exception */
}
- return 1; /* Normal non-ast check return */
+ regs->rax = rval;
+
+ return rval; /* Normal non-ast check return */
+}
+
+void cpu_powerstats(__unused void *arg) {
+ cpu_data_t *cdp = current_cpu_datap();
+ int cnum = cdp->cpu_number;
+ uint32_t cl = 0, ch = 0, mpl = 0, mph = 0, apl = 0, aph = 0;
+
+ rdmsr_carefully(MSR_IA32_MPERF, &mpl, &mph);
+ rdmsr_carefully(MSR_IA32_APERF, &apl, &aph);
+
+ cdp->cpu_mperf = ((uint64_t)mph << 32) | mpl;
+ cdp->cpu_aperf = ((uint64_t)aph << 32) | apl;
+
+ if (cnum & 1)
+ return;
+
+ rdmsr_carefully(MSR_IA32_CORE_C3_RESIDENCY, &cl, &ch);
+ cdp->cpu_c3res = ((uint64_t)ch << 32) | cl;
+
+ rdmsr_carefully(MSR_IA32_CORE_C6_RESIDENCY, &cl, &ch);
+ cdp->cpu_c6res = ((uint64_t)ch << 32) | cl;
+
+ rdmsr_carefully(MSR_IA32_CORE_C7_RESIDENCY, &cl, &ch);
+ cdp->cpu_c7res = ((uint64_t)ch << 32) | cl;
}
#define dgBootScreen 7
#define dgFlush 8
#define dgAlign 9
-#define dgprw 10
+#define dgGzallocTest 10
#define dgmck 11
#define dg64 12
#define dgProbeRead 13
#define dgCPNull 14
#define dgPerfMon 15
#define dgMapPage 16
-#define dgGzallocTest 17
+#define dgPowerStat 17
#define dgBind 18
#define dgAcntg 20
#define dgKlra 21
uint64_t cpu_pmap_pcid_preserves;
#endif
#endif /* x86_64 */
+ uint64_t cpu_aperf;
+ uint64_t cpu_mperf;
+ uint64_t cpu_c3res;
+ uint64_t cpu_c6res;
+ uint64_t cpu_c7res;
+ uint64_t cpu_itime_total;
+ uint64_t cpu_rtime_total;
+ uint64_t cpu_rtimes[4];
+ uint64_t cpu_itimes[4];
+ uint64_t cpu_ixtime;
uint64_t cpu_max_observed_int_latency;
int cpu_max_observed_int_latency_vector;
uint64_t debugger_entry_time;
void *pmStats; /* Power Management stats for package*/
void *pmState; /* Power Management state for package*/
struct mca_state *mca_state; /* MCA state for memory errors */
+ uint32_t num_idle;
} x86_pkg_t;
extern x86_pkg_t *x86_pkgs; /* root of all CPU packages */
iavx->fp_save_layout = thread_is_64bit(thr_act) ? XSAVE64 : XSAVE32;
/* Sanitize XSAVE header */
bzero(&iavx->_xh.xhrsvd[0], sizeof(iavx->_xh.xhrsvd));
- if (state_size == sizeof(struct x86_avx_thread_state))
+ if (fpu_nyreg)
iavx->_xh.xsbv = (XFEM_YMM | XFEM_SSE | XFEM_X87);
else
iavx->_xh.xsbv = (XFEM_SSE | XFEM_X87);
return get_interrupt_level() != 0;
}
+void ml_get_power_state(boolean_t *icp, boolean_t *pidlep) {
+ *icp = (get_interrupt_level() != 0);
+ /* These will be technically inaccurate for interrupts that occur
+ * successively within a single "idle exit" event, but shouldn't
+ * matter statistically.
+ */
+ *pidlep = (current_cpu_datap()->lcpu.package->num_idle == topoParms.nLThreadsPerPackage);
+}
+
/* Generate a fake interrupt */
void ml_cause_interrupt(void)
{
void interrupt_latency_tracker_setup(void);
void interrupt_reset_latency_stats(void);
void interrupt_populate_latency_stats(char *, unsigned);
+void ml_get_power_state(boolean_t *, boolean_t *);
#endif /* XNU_KERNEL_PRIVATE */
#endif /* _I386_MACHINE_ROUTINES_H_ */
+
/*
* Copyright (c) 2009 Apple Inc. All rights reserved.
*
/* Include a PAL-specific header, too, for xnu-internal overrides */
#include <i386/pal_native.h>
+extern boolean_t virtualized;
+#define PAL_VIRTUALIZED_PROPERTY_VALUE 4
/* Allow for tricky IOKit property matching */
#define PAL_AICPM_PROPERTY_NAME "intel_cpupm_matching"
static inline void
pal_get_resource_property(const char **property_name, int *property_value)
{
- *property_name = PAL_AICPM_PROPERTY_NAME;
- *property_value = PAL_AICPM_PROPERTY_VALUE;
+ *property_name = PAL_AICPM_PROPERTY_NAME;
+ *property_value = PAL_AICPM_PROPERTY_VALUE;
+ if (virtualized)
+ *property_value = PAL_VIRTUALIZED_PROPERTY_VALUE;
}
/* assembly function to update TSC / timebase info */
(*pmDispatch->cstateInit)();
}
+#define CPU_ACTIVE_STAT_BIN_1 (500000)
+#define CPU_ACTIVE_STAT_BIN_2 (2000000)
+#define CPU_ACTIVE_STAT_BIN_3 (5000000)
+
+#define CPU_IDLE_STAT_BIN_1 (500000)
+#define CPU_IDLE_STAT_BIN_2 (2000000)
+#define CPU_IDLE_STAT_BIN_3 (5000000)
+
/*
* Called when the CPU is idle. It calls into the power management kext
* to determine the best way to idle the CPU.
machine_idle(void)
{
cpu_data_t *my_cpu = current_cpu_datap();
+ uint64_t ctime, rtime, itime;
if (my_cpu == NULL)
goto out;
+ ctime = mach_absolute_time();
+
my_cpu->lcpu.state = LCPU_IDLE;
DBGLOG(cpu_handle, cpu_number(), MP_IDLE);
MARK_CPU_IDLE(cpu_number());
+ rtime = ctime - my_cpu->cpu_ixtime;
+
+ my_cpu->cpu_rtime_total += rtime;
+
+ if (rtime < CPU_ACTIVE_STAT_BIN_1)
+ my_cpu->cpu_rtimes[0]++;
+ else if (rtime < CPU_ACTIVE_STAT_BIN_2)
+ my_cpu->cpu_rtimes[1]++;
+ else if (rtime < CPU_ACTIVE_STAT_BIN_3)
+ my_cpu->cpu_rtimes[2]++;
+ else
+ my_cpu->cpu_rtimes[3]++;
+
+
if (pmInitDone) {
/*
* Handle case where ml_set_maxbusdelay() or ml_set_maxintdelay()
*/
MARK_CPU_ACTIVE(cpu_number());
DBGLOG(cpu_handle, cpu_number(), MP_UNIDLE);
+
+ uint64_t ixtime = my_cpu->cpu_ixtime = mach_absolute_time();
+ itime = ixtime - ctime;
+
my_cpu->lcpu.state = LCPU_RUN;
+ if (itime < CPU_IDLE_STAT_BIN_1)
+ my_cpu->cpu_itimes[0]++;
+ else if (itime < CPU_IDLE_STAT_BIN_2)
+ my_cpu->cpu_itimes[1]++;
+ else if (itime < CPU_IDLE_STAT_BIN_3)
+ my_cpu->cpu_itimes[2]++;
+ else
+ my_cpu->cpu_itimes[3]++;
+
+ my_cpu->cpu_itime_total += itime;
+
+
/*
* Re-enable interrupts.
*/
kern_return_t
pmCPUExitHaltToOff(int cpu)
{
- kern_return_t rc = KERN_INVALID_ARGUMENT;
+ kern_return_t rc = KERN_SUCCESS;
if (pmInitDone
&& pmDispatch != NULL
{
return(KERN_SUCCESS);
}
+
+void machine_track_platform_idle(boolean_t entry) {
+ cpu_data_t *my_cpu = current_cpu_datap();
+
+ if (entry) {
+ (void)__sync_fetch_and_add(&my_cpu->lcpu.package->num_idle, 1);
+ }
+ else {
+ (void)__sync_fetch_and_sub(&my_cpu->lcpu.package->num_idle, 1);
+ }
+}
#define MSR_PLATFORM_INFO 0xce
+#define MSR_IA32_MPERF 0xE7
+#define MSR_IA32_APERF 0xE8
+
#define MSR_PMG_CST_CONFIG_CONTROL 0xe2
#define MSR_IA32_BBL_CR_CTL 0x119
#define MSR_IA32_MTRR_FIX4K_F0000 0x26e
#define MSR_IA32_MTRR_FIX4K_F8000 0x26f
+#define MSR_IA32_PKG_C3_RESIDENCY 0x3F8
+#define MSR_IA32_PKG_C6_RESIDENCY 0x3F9
+#define MSR_IA32_PKG_C7_RESIDENCY 0x3FA
+
+#define MSR_IA32_CORE_C3_RESIDENCY 0x3FC
+#define MSR_IA32_CORE_C6_RESIDENCY 0x3FD
+#define MSR_IA32_CORE_C7_RESIDENCY 0x3FE
+
#define MSR_IA32_MC0_CTL 0x400
#define MSR_IA32_MC0_STATUS 0x401
#define MSR_IA32_MC0_ADDR 0x402
#define MSR_IA32_DS_AREA 0x600
-#define MSR_IA32_PACKAGE_POWER_SKU_UNIT 0x606
-#define MSR_IA32_PACKAGE_ENERY_STATUS 0x611
+#define MSR_IA32_PKG_POWER_SKU_UNIT 0x606
+#define MSR_IA32_PKG_C2_RESIDENCY 0x60D
+#define MSR_IA32_PKG_ENERGY_STATUS 0x611
#define MSR_IA32_PRIMARY_PLANE_ENERY_STATUS 0x639
#define MSR_IA32_SECONDARY_PLANE_ENERY_STATUS 0x641
#define MSR_IA32_TSC_DEADLINE 0x6e0
return (KERN_SUCCESS);
}
+ case HOST_EXPIRED_TASK_INFO:
+ {
+ if (*count < TASK_POWER_INFO_COUNT) {
+ return (KERN_FAILURE);
+ }
+
+ task_power_info_t tinfo = (task_power_info_t)info;
+
+ tinfo->task_interrupt_wakeups = dead_task_statistics.task_interrupt_wakeups;
+ tinfo->task_platform_idle_wakeups = dead_task_statistics.task_platform_idle_wakeups;
+
+ tinfo->task_timer_wakeups_bin_1 = dead_task_statistics.task_timer_wakeups_bin_1;
+ tinfo->task_timer_wakeups_bin_2 = dead_task_statistics.task_timer_wakeups_bin_2;
+
+ tinfo->total_user = dead_task_statistics.total_user_time;
+ tinfo->total_system = dead_task_statistics.total_system_time;
+
+ return (KERN_SUCCESS);
+ }
+
default:
return (KERN_INVALID_ARGUMENT);
}
extern vm_extmod_statistics_data_t host_extmod_statistics;
+typedef struct {
+ uint64_t total_user_time;
+ uint64_t total_system_time;
+ uint64_t task_interrupt_wakeups;
+ uint64_t task_platform_idle_wakeups;
+ uint64_t task_timer_wakeups_bin_1;
+ uint64_t task_timer_wakeups_bin_2;
+} expired_task_statistics_t;
+
+extern expired_task_statistics_t dead_task_statistics;
+
#endif /* MACH_KERNEL_PRIVATE */
/*
extern void machine_idle(void);
+extern void machine_track_platform_idle(boolean_t);
+
extern void machine_signal_idle(
processor_t processor);
void *free_pages;
struct processor_sched_statistics sched_stats;
+ uint64_t timer_call_ttd; /* current timer call time-to-deadline */
};
typedef struct processor_data processor_data_t;
static boolean_t sched_traditional_use_pset_runqueue = FALSE;
+/* Defaults for timer deadline profiling */
+#define TIMER_DEADLINE_TRACKING_BIN_1_DEFAULT 2000000 /* Timers with deadlines <=
+ * 2ms */
+#define TIMER_DEADLINE_TRACKING_BIN_2_DEFAULT 5000000 /* Timers with deadlines
+ <= 5ms */
+uint64_t timer_deadline_tracking_bin_1;
+uint64_t timer_deadline_tracking_bin_2;
+
__attribute__((always_inline))
static inline run_queue_t runq_for_processor(processor_t processor)
{
static void
sched_realtime_timebase_init(void);
+static void
+sched_timer_deadline_tracking_init(void);
+
#if defined(CONFIG_SCHED_TRADITIONAL)
static void
sched_traditional_tick_continue(void);
SCHED(fairshare_init)();
sched_realtime_init();
ast_init();
+ sched_timer_deadline_tracking_init();
SCHED(pset_init)(&pset0);
SCHED(processor_init)(master_processor);
wait_result_t wresult)
{
boolean_t result = FALSE;
+ thread_t cthread = current_thread();
/*
* Set wait_result.
thread->computation_metered = 0;
thread->reason = AST_NONE;
+ /* Obtain power-relevant interrupt and "platform-idle exit" statistics.
+ * We also account for "double hop" thread signaling via
+ * the thread callout infrastructure.
+ * DRK: consider removing the callout wakeup counters in the future
+ * they're present for verification at the moment.
+ */
+ boolean_t aticontext, pidle;
+ ml_get_power_state(&aticontext, &pidle);
+ if (__improbable(aticontext)) {
+ ledger_credit(thread->t_ledger, task_ledgers.interrupt_wakeups, 1);
+ uint64_t ttd = PROCESSOR_DATA(current_processor(), timer_call_ttd);
+ if (ttd) {
+ if (ttd <= timer_deadline_tracking_bin_1)
+ thread->thread_timer_wakeups_bin_1++;
+ else
+ if (ttd <= timer_deadline_tracking_bin_2)
+ thread->thread_timer_wakeups_bin_2++;
+ }
+ if (pidle) {
+ ledger_credit(thread->t_ledger, task_ledgers.platform_idle_wakeups, 1);
+ }
+ } else if (thread_get_tag_internal(cthread) & THREAD_TAG_CALLOUT) {
+ if (cthread->callout_woken_from_icontext) {
+ ledger_credit(thread->t_ledger, task_ledgers.interrupt_wakeups, 1);
+ thread->thread_callout_interrupt_wakeups++;
+ if (cthread->callout_woken_from_platform_idle) {
+ ledger_credit(thread->t_ledger, task_ledgers.platform_idle_wakeups, 1);
+ thread->thread_callout_platform_idle_wakeups++;
+ }
+ }
+ }
+
+ if (thread_get_tag_internal(thread) & THREAD_TAG_CALLOUT) {
+ thread->callout_woken_from_icontext = aticontext;
+ thread->callout_woken_from_platform_idle = pidle;
+ }
+
/* Event should only be triggered if thread is not already running */
if (result == FALSE) {
KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
IDLE_KERNEL_DEBUG_CONSTANT(
MACHDBG_CODE(DBG_MACH_SCHED,MACH_IDLE) | DBG_FUNC_NONE, (uintptr_t)thread_tid(thread), rt_runq.count, SCHED(processor_runq_count)(processor), -1, 0);
+ machine_track_platform_idle(TRUE);
+
machine_idle();
+ machine_track_platform_idle(FALSE);
+
(void)splsched();
IDLE_KERNEL_DEBUG_CONSTANT(
return ((thread->state & (TH_RUN|TH_WAIT)) == TH_RUN);
}
#endif /* DEBUG */
+
+static void
+sched_timer_deadline_tracking_init(void) {
+ nanoseconds_to_absolutetime(TIMER_DEADLINE_TRACKING_BIN_1_DEFAULT, &timer_deadline_tracking_bin_1);
+ nanoseconds_to_absolutetime(TIMER_DEADLINE_TRACKING_BIN_2_DEFAULT, &timer_deadline_tracking_bin_2);
+}
zinfo_usage_store_t tasks_tkm_private;
zinfo_usage_store_t tasks_tkm_shared;
+/* A container to accumulate statistics for expired tasks */
+expired_task_statistics_t dead_task_statistics;
+lck_spin_t dead_task_statistics_lock;
+
static ledger_template_t task_ledger_template = NULL;
-struct _task_ledger_indices task_ledgers = {-1, -1, -1, -1, -1};
+struct _task_ledger_indices task_ledgers = {-1, -1, -1, -1, -1, -1, -1};
void init_task_ledgers(void);
vm_map_deallocate(kernel_task->map);
kernel_task->map = kernel_map;
-
+ lck_spin_init(&dead_task_statistics_lock, &task_lck_grp, &task_lck_attr);
}
/*
"bytes");
task_ledgers.wired_mem = ledger_entry_add(t, "wired_mem", "physmem",
"bytes");
+ task_ledgers.platform_idle_wakeups = ledger_entry_add(t, "platform_idle_wakeups", "power",
+ "count");
+ task_ledgers.interrupt_wakeups = ledger_entry_add(t, "interrupt_wakeups", "power",
+ "count");
if ((task_ledgers.cpu_time < 0) || (task_ledgers.tkm_private < 0) ||
(task_ledgers.tkm_shared < 0) || (task_ledgers.phys_mem < 0) ||
- (task_ledgers.wired_mem < 0)) {
+ (task_ledgers.wired_mem < 0) || (task_ledgers.platform_idle_wakeups < 0) ||
+ (task_ledgers.interrupt_wakeups < 0)) {
panic("couldn't create entries for task ledger template");
}
}
bzero(&new_task->extmod_statistics, sizeof(new_task->extmod_statistics));
+ new_task->task_timer_wakeups_bin_1 = new_task->task_timer_wakeups_bin_2 = 0;
lck_mtx_lock(&tasks_threads_lock);
queue_enter(&tasks, new_task, task_t, tasks);
task_deallocate(
task_t task)
{
- ledger_amount_t credit, debit;
+ ledger_amount_t credit, debit, interrupt_wakeups, platform_idle_wakeups;
if (task == TASK_NULL)
return;
vm_map_deallocate(task->map);
is_release(task->itk_space);
+ ledger_get_entries(task->ledger, task_ledgers.interrupt_wakeups,
+ &interrupt_wakeups, &debit);
+ ledger_get_entries(task->ledger, task_ledgers.platform_idle_wakeups,
+ &platform_idle_wakeups, &debit);
+
+ /* Accumulate statistics for dead tasks */
+ lck_spin_lock(&dead_task_statistics_lock);
+ dead_task_statistics.total_user_time += task->total_user_time;
+ dead_task_statistics.total_system_time += task->total_system_time;
+
+ dead_task_statistics.task_interrupt_wakeups += interrupt_wakeups;
+ dead_task_statistics.task_platform_idle_wakeups += platform_idle_wakeups;
+
+ dead_task_statistics.task_timer_wakeups_bin_1 += task->task_timer_wakeups_bin_1;
+ dead_task_statistics.task_timer_wakeups_bin_2 += task->task_timer_wakeups_bin_2;
+
+ lck_spin_unlock(&dead_task_statistics_lock);
lck_mtx_destroy(&task->lock, &task_lck_grp);
#if CONFIG_MACF_MACH
error = task_affinity_info(task, task_info_out, task_info_count);
break;
}
+
+ case TASK_POWER_INFO:
+ {
+ task_power_info_t info;
+ thread_t thread;
+ ledger_amount_t tmp;
+
+ if (*task_info_count < TASK_POWER_INFO_COUNT) {
+ error = KERN_INVALID_ARGUMENT;
+ break;
+ }
+
+ info = (task_power_info_t)task_info_out;
+
+ ledger_get_entries(task->ledger, task_ledgers.interrupt_wakeups,
+ (ledger_amount_t *)&info->task_interrupt_wakeups, &tmp);
+ ledger_get_entries(task->ledger, task_ledgers.platform_idle_wakeups,
+ (ledger_amount_t *)&info->task_platform_idle_wakeups, &tmp);
+
+ info->task_timer_wakeups_bin_1 = task->task_timer_wakeups_bin_1;
+ info->task_timer_wakeups_bin_2 = task->task_timer_wakeups_bin_2;
+
+ info->total_user = task->total_user_time;
+ info->total_system = task->total_system_time;
+
+ queue_iterate(&task->threads, thread, thread_t, task_threads) {
+ uint64_t tval;
+ spl_t x;
+
+ if ((task == kernel_task) && (thread->priority == IDLEPRI) && (thread->sched_pri == IDLEPRI))
+ continue;
+ x = splsched();
+ thread_lock(thread);
+
+ info->task_timer_wakeups_bin_1 += thread->thread_timer_wakeups_bin_1;
+ info->task_timer_wakeups_bin_2 += thread->thread_timer_wakeups_bin_2;
+
+ tval = timer_grab(&thread->user_timer);
+ info->total_user += tval;
+
+ tval = timer_grab(&thread->system_timer);
+ if (thread->precise_user_kernel_time) {
+ info->total_system += tval;
+ } else {
+ /* system_timer may represent either sys or user */
+ info->total_user += tval;
+ }
+
+ thread_unlock(thread);
+ splx(x);
+ }
+ break;
+ }
+
default:
error = KERN_INVALID_ARGUMENT;
}
vm_extmod_statistics_data_t extmod_statistics;
natural_t proc_terminate; /* the process is marked for proc_terminate */
+
+ /* Statistics accumulated for terminated threads from this task */
+ uint32_t task_timer_wakeups_bin_1;
+ uint32_t task_timer_wakeups_bin_2;
};
#define task_lock(task) lck_mtx_lock(&(task)->lock)
int tkm_shared;
int phys_mem;
int wired_mem;
+ int platform_idle_wakeups;
+ int interrupt_wakeups;
};
extern struct _task_ledger_indices task_ledgers;
task->syscalls_unix += thread->syscalls_unix;
task->syscalls_mach += thread->syscalls_mach;
+ task->task_timer_wakeups_bin_1 += thread->thread_timer_wakeups_bin_1;
+ task->task_timer_wakeups_bin_2 += thread->thread_timer_wakeups_bin_2;
queue_remove(&task->threads, thread, thread_t, task_threads);
task->thread_count--;
return (thread != THREAD_NULL? thread->thread_id: 0);
}
+uint16_t
+thread_set_tag(thread_t th, uint16_t tag) {
+ return thread_set_tag_internal(th, tag);
+}
+uint16_t
+thread_get_tag(thread_t th) {
+ return thread_get_tag_internal(th);
+}
+
uint64_t
thread_dispatchqaddr(
thread_t thread)
#define TH_OPT_SYSTEM_CRITICAL 0x10 /* Thread must always be allowed to run - even under heavy load */
#define TH_OPT_PROC_CPULIMIT 0x20 /* Thread has a task-wide CPU limit applied to it */
#define TH_OPT_PRVT_CPULIMIT 0x40 /* Thread has a thread-private CPU limit applied to it */
+#define TH_OPT_IDLE_THREAD 0x0080 /* Thread is a per-processor idle thread */
/* Data updated during assert_wait/thread_wakeup */
decl_simple_lock_data(,sched_lock) /* scheduling lock (thread_lock()) */
task_watch_t * taskwatch; /* task watch */
integer_t saved_importance; /* saved task-relative importance */
#endif /* CONFIG_EMBEDDED */
+ uint32_t thread_callout_interrupt_wakeups;
+ uint32_t thread_callout_platform_idle_wakeups;
+ uint32_t thread_timer_wakeups_bin_1;
+ uint32_t thread_timer_wakeups_bin_2;
+ uint16_t thread_tag;
+ uint16_t callout_woken_from_icontext:1,
+ callout_woken_from_platform_idle:1,
+ thread_bitfield_unused:14;
+
};
#define ith_state saved.receive.state
extern void funnel_unlock(
struct funnel_lock *lock);
+static inline uint16_t thread_set_tag_internal(thread_t thread, uint16_t tag) {
+ return __sync_fetch_and_or(&thread->thread_tag, tag);
+}
+static inline uint16_t thread_get_tag_internal(thread_t thread) {
+ return thread->thread_tag;
+}
+
#else /* MACH_KERNEL_PRIVATE */
__BEGIN_DECLS
#ifdef XNU_KERNEL_PRIVATE
+/*
+ * Thread tags; for easy identification.
+ */
+#define THREAD_TAG_MAINTHREAD 0x1
+#define THREAD_TAG_CALLOUT 0x2
+#define THREAD_TAG_IOWORKLOOP 0x4
+
+uint16_t thread_set_tag(thread_t, uint16_t);
+uint16_t thread_get_tag(thread_t);
+
extern kern_return_t thread_state_initialize(
thread_t thread);
#include <libkern/OSAtomic.h>
#include <sys/kdebug.h>
-
+#if CONFIG_DTRACE
+#include <mach/sdt.h>
+#endif
static zone_t thread_call_zone;
static struct wait_queue daemon_wqueue;
boolean_t result = TRUE;
thread_call_group_t group;
spl_t s;
+ uint64_t abstime;
group = thread_call_get_group(call);
s = splsched();
thread_call_lock_spin();
+ abstime = mach_absolute_time();
result = _delayed_call_enqueue(call, group, deadline);
call->tc_call.param1 = param1;
+ call->ttd = (deadline > abstime) ? (deadline - abstime) : 0;
+#if CONFIG_DTRACE
+ DTRACE_TMR4(thread_callout__create, thread_call_func_t, call->tc_call.func, 0, (call->ttd >> 32), (unsigned) (call->ttd & 0xFFFFFFFF));
+#endif
thread_call_unlock();
splx(s);
thread_call_unlock();
splx(s);
+#if CONFIG_DTRACE
+ DTRACE_TMR4(thread_callout__cancel, thread_call_func_t, call->tc_call.func, 0, (call->ttd >> 32), (unsigned) (call->ttd & 0xFFFFFFFF));
+#endif
return (result);
}
thread_t self = current_thread();
boolean_t canwait;
+ if ((thread_get_tag_internal(self) & THREAD_TAG_CALLOUT) == 0)
+ (void)thread_set_tag_internal(self, THREAD_TAG_CALLOUT);
+
/*
* A wakeup with THREAD_INTERRUPTED indicates that
* we should terminate.
uint32_t tc_flags;
int32_t tc_refs;
+
+ uint64_t ttd; /* Time to deadline at creation */
};
#define THREAD_CALL_ALLOC 0x01
#include <sys/kdebug.h>
-#if CONFIG_DTRACE && (DEVELOPMENT || DEBUG )
+#if CONFIG_DTRACE
#include <mach/sdt.h>
#endif
call->soft_deadline = deadline;
}
#endif
+ call->ttd = call->soft_deadline - ctime;
+
+#if CONFIG_DTRACE
+ DTRACE_TMR6(callout__create, timer_call_func_t, CE(call)->func,
+ timer_call_param_t, CE(call)->param0, uint32_t, call->flags,
+ (deadline - call->soft_deadline),
+ (call->ttd >> 32), (unsigned) (call->ttd & 0xFFFFFFFF));
+#endif
+
queue = timer_queue_assign(deadline);
old_queue = timer_call_enqueue_deadline_unlocked(call, queue, deadline);
}
splx(s);
+#if CONFIG_DTRACE
+ DTRACE_TMR6(callout__cancel, timer_call_func_t, CE(call)->func,
+ timer_call_param_t, CE(call)->param0, uint32_t, call->flags, 0,
+ (call->ttd >> 32), (unsigned) (call->ttd & 0xFFFFFFFF));
+#endif
+
return (old_queue != NULL);
}
DECR_TIMER_CALLOUT | DBG_FUNC_START,
VM_KERNEL_UNSLIDE(func), param0, param1, 0, 0);
-#if CONFIG_DTRACE && (DEVELOPMENT || DEBUG )
- DTRACE_TMR3(callout__start, timer_call_func_t, func,
- timer_call_param_t, param0,
- timer_call_param_t, param1);
+#if CONFIG_DTRACE
+ DTRACE_TMR6(callout__start, timer_call_func_t, func,
+ timer_call_param_t, param0, unsigned, call->flags,
+ 0, (call->ttd >> 32),
+ (unsigned) (call->ttd & 0xFFFFFFFF));
#endif
+ /* Maintain time-to-deadline in per-processor data
+ * structure for thread wakeup deadline statistics.
+ */
+ uint64_t *ttdp = &(PROCESSOR_DATA(current_processor(), timer_call_ttd));
+ *ttdp = call->ttd;
(*func)(param0, param1);
+ *ttdp = 0;
-#if CONFIG_DTRACE && (DEVELOPMENT || DEBUG )
- DTRACE_TMR3(callout__end, timer_call_func_t, func,
- timer_call_param_t, param0,
- timer_call_param_t, param1);
+#if CONFIG_DTRACE
+ DTRACE_TMR3(callout__end, timer_call_func_t, func,
+ timer_call_param_t, param0, timer_call_param_t,
+ param1);
#endif
KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
uint32_t flags;
boolean_t async_dequeue; /* this field is protected by
call_entry queue's lock */
+ uint64_t ttd; /* Time to deadline at creation */
} *timer_call_t;
typedef void *timer_call_param_t;
/* host_statistics64() */
#define HOST_VM_INFO64 4 /* 64-bit virtual memory stats */
#define HOST_EXTMOD_INFO64 5 /* External modification stats */
-
+#define HOST_EXPIRED_TASK_INFO 6 /* Statistics for expired tasks */
struct host_load_info {
integer_t avenrun[3]; /* scaled by LOAD_SCALE */
#define DTRACE_TMR3(name, type1, arg1, type2, arg2, type3, arg3) \
DTRACE_PROBE3(__sdt_, name, arg1, arg2, arg3);
+#define DTRACE_TMR4(name, type1, arg1, arg2, arg3, arg4) \
+ DTRACE_PROBE4(__sdt_, name, arg1, arg2, arg3, arg4);
+
+#define DTRACE_TMR5(name, type1, arg1, type2, arg2, type3, arg3, arg4, arg5) \
+ DTRACE_PROBE5(__sdt_, name, arg1, arg2, arg3, arg4, arg5);
+
+#define DTRACE_TMR6(name, type1, arg1, type2, arg2, type3, arg3, arg4, arg5, arg6) \
+ DTRACE_PROBE6(__sdt_, name, arg1, arg2, arg3, arg4, arg5, arg6);
+
#define DTRACE_VM(name) \
DTRACE_PROBE(__vminfo_, name)
/* Always 64-bit in user and kernel */
#define MACH_TASK_BASIC_INFO 20 /* always 64-bit basic info */
+#define TASK_POWER_INFO 21
+struct task_power_info {
+ uint64_t total_user;
+ uint64_t total_system;
+ uint64_t task_interrupt_wakeups;
+ uint64_t task_platform_idle_wakeups;
+ uint64_t task_timer_wakeups_bin_1;
+ uint64_t task_timer_wakeups_bin_2;
+};
+typedef struct task_power_info task_power_info_data_t;
+typedef struct task_power_info *task_power_info_t;
+#define TASK_POWER_INFO_COUNT ((mach_msg_type_number_t) \
+ (sizeof (task_power_info_data_t) / sizeof (natural_t)))
+
struct mach_task_basic_info {
mach_vm_size_t virtual_size; /* virtual memory size (bytes) */
mach_vm_size_t resident_size; /* resident memory size (bytes) */
struct vnode *dvp, struct vnode *vp, struct componentname *cnp);
void mac_vnode_notify_rename(vfs_context_t ctx, struct vnode *vp,
struct vnode *dvp, struct componentname *cnp);
+void mac_vnode_notify_open(vfs_context_t ctx, struct vnode *vp, int acc_flags);
int vnode_label(struct mount *mp, struct vnode *dvp, struct vnode *vp,
struct componentname *cnp, int flags, vfs_context_t ctx);
void vnode_relabel(struct vnode *vp);
struct componentname *cnp
);
+/**
+ @brief Inform MAC policies that a vnode has been opened
+ @param cred User credential for the creating process
+ @param vp vnode opened
+ @param label Policy label for the vp
+ @param acc_mode open(2) access mode used
+
+ Inform Mac policies that a vnode have been successfully opened
+ (passing all MAC polices and DAC).
+*/
+typedef void mpo_vnode_notify_open_t(
+ kauth_cred_t cred,
+ struct vnode *vp,
+ struct label *label,
+ int acc_mode
+);
+
/**
@brief Inform MAC policies that a vnode has been renamed
@param cred User credential for the renaming process
mpo_thread_label_destroy_t *mpo_thread_label_destroy;
mpo_system_check_kas_info_t *mpo_system_check_kas_info;
mpo_reserved_hook_t *mpo_reserved18;
- mpo_reserved_hook_t *mpo_reserved19;
+ mpo_vnode_notify_open_t *mpo_vnode_notify_open;
mpo_reserved_hook_t *mpo_reserved20;
mpo_reserved_hook_t *mpo_reserved21;
mpo_reserved_hook_t *mpo_reserved22;
dvp, dvp->v_label, cnp);
}
+void
+mac_vnode_notify_open(vfs_context_t ctx, struct vnode *vp, int acc_flags)
+{
+ kauth_cred_t cred;
+
+ if (!mac_vnode_enforce ||
+ !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
+ return;
+
+ cred = vfs_context_ucred(ctx);
+ MAC_PERFORM(vnode_notify_open, cred, vp, vp->v_label, acc_flags);
+}
+
/*
* Extended attribute 'name' was updated via
* vn_setxattr() or vn_removexattr(). Allow the