]> git.saurik.com Git - apple/libc.git/blame - sys/OSMemoryNotification.c
Libc-498.1.5.tar.gz
[apple/libc.git] / sys / OSMemoryNotification.c
CommitLineData
b5d655f7
A
1/*
2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <errno.h>
25#include <libkern/OSMemoryNotification.h>
26#include <mach/mach.h>
27#include <notify.h>
28#include <stdlib.h>
29#include <sys/time.h>
30
31const char *kOSMemoryNotificationName = "com.apple.system.memorystatus";
32
33struct _OSMemoryNotification {
34 int token;
35 mach_port_t port;
36};
37
38int
39OSMemoryNotificationCreate(OSMemoryNotificationRef *note)
40{
41 OSMemoryNotificationRef ref = malloc(sizeof(struct _OSMemoryNotification));
42
43 if (NULL == ref) {
44 return ENOMEM;
45 }
46
47 if (NOTIFY_STATUS_OK != notify_register_mach_port(kOSMemoryNotificationName, &ref->port, 0, &ref->token))
48 return ENOMEM;
49
50 *note = ref;
51
52 return 0;
53}
54
55int
56OSMemoryNotificationDestroy(OSMemoryNotificationRef note)
57{
58 if (NOTIFY_STATUS_OK != notify_cancel(note->token))
59 return EINVAL;
60
61 if (KERN_SUCCESS != mach_port_deallocate(mach_task_self(), note->port))
62 return EINVAL;
63
64 free(note);
65
66 return 0;
67}
68
69int
70OSMemoryNotificationWait(OSMemoryNotificationRef note, OSMemoryNotificationLevel *level)
71{
72
73 return OSMemoryNotificationTimedWait(note, level, NULL);
74}
75
76static mach_msg_timeout_t
77abs_to_timeout(const struct timeval *abstime)
78{
79 struct timeval rel, now;
80
81 gettimeofday(&now, NULL);
82
83 rel.tv_usec = abstime->tv_usec - now.tv_usec;
84 rel.tv_sec = abstime->tv_sec - now.tv_sec;
85 if (rel.tv_usec < 0) {
86 rel.tv_usec += 1000000;
87 rel.tv_sec--;
88 }
89 if (((int)rel.tv_sec < 0) || ((rel.tv_sec == 0) && (rel.tv_usec == 0))) {
90 return 0;
91 }
92 return rel.tv_sec * 1000 + rel.tv_usec / 1000;
93}
94
95int
96OSMemoryNotificationTimedWait(OSMemoryNotificationRef note, OSMemoryNotificationLevel *level, const struct timeval *abstime)
97{
98 mach_msg_empty_rcv_t msg = {{0}};
99 mach_msg_return_t ret;
100 uint64_t val;
101
102 if (abstime) {
103 mach_msg_timeout_t timeout = abs_to_timeout(abstime);
104
105 if (0 == timeout)
106 return ETIMEDOUT;
107
108 ret = mach_msg(&msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof msg, note->port, timeout, MACH_PORT_NULL);
109
110 if (MACH_RCV_TIMED_OUT == ret) {
111 return ETIMEDOUT;
112 }
113 } else {
114 ret = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof msg, note->port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
115 }
116
117 if (MACH_MSG_SUCCESS != ret)
118 return EINVAL;
119
120 if (NOTIFY_STATUS_OK != notify_get_state(note->token, &val))
121 return EINVAL;
122
123 *level = (OSMemoryNotificationLevel)val;
124
125 return 0;
126}
127
128OSMemoryNotificationLevel OSMemoryNotificationCurrentLevel(void)
129{
130 uint64_t val;
131 int token;
132
133 if (NOTIFY_STATUS_OK != notify_register_check(kOSMemoryNotificationName, &token))
134 return OSMemoryNotificationLevelAny;
135
136 if (NOTIFY_STATUS_OK != notify_get_state(token, &val))
137 return OSMemoryNotificationLevelAny;
138
139 if (NOTIFY_STATUS_OK != notify_cancel(token))
140 return OSMemoryNotificationLevelAny;
141
142 return (OSMemoryNotificationLevel)val;
143}