1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 * Permission is hereby granted, free of charge, to any person obtaining a copy
3 * of this software and associated documentation files (the "Software"), to
4 * deal in the Software without restriction, including without limitation the
5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6 * sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
43 #include <sys/protosw.h>
44 #include <libperfstat.h>
46 #include <sys/procfs.h>
48 uint64_t uv__hrtime(void) {
49 uint64_t G
= 1000000000;
51 read_wall_time(&t
, TIMEBASE_SZ
);
52 time_base_to_time(&t
, TIMEBASE_SZ
);
53 return (uint64_t) t
.tb_high
* G
+ t
.tb_low
;
58 * We could use a static buffer for the path manipulations that we need outside
59 * of the function, but this function could be called by multiple consumers and
60 * we don't want to potentially create a race condition in the use of snprintf.
62 int uv_exepath(char* buffer
, size_t* size
) {
64 char pp
[64], cwdl
[PATH_MAX
];
75 (void) snprintf(pp
, sizeof(pp
), "/proc/%lu/cwd", (unsigned long) getpid());
77 res
= readlink(pp
, cwdl
, sizeof(cwdl
) - 1);
84 (void) snprintf(pp
, sizeof(pp
), "/proc/%lu/psinfo", (unsigned long) getpid());
85 fd
= open(pp
, O_RDONLY
);
89 res
= read(fd
, &ps
, sizeof(ps
));
94 (void) snprintf(buffer
, *size
, "%s%s", cwdl
, ps
.pr_fname
);
95 *size
= strlen(buffer
);
100 uint64_t uv_get_free_memory(void) {
101 perfstat_memory_total_t mem_total
;
102 int result
= perfstat_memory_total(NULL
, &mem_total
, sizeof(mem_total
), 1);
106 return mem_total
.real_free
* 4096;
110 uint64_t uv_get_total_memory(void) {
111 perfstat_memory_total_t mem_total
;
112 int result
= perfstat_memory_total(NULL
, &mem_total
, sizeof(mem_total
), 1);
116 return mem_total
.real_total
* 4096;
120 void uv_loadavg(double avg
[3]) {
121 perfstat_cpu_total_t ps_total
;
122 int result
= perfstat_cpu_total(NULL
, &ps_total
, sizeof(ps_total
), 1);
124 avg
[0] = 0.; avg
[1] = 0.; avg
[2] = 0.;
127 avg
[0] = ps_total
.loadavg
[0] / (double)(1 << SBITS
);
128 avg
[1] = ps_total
.loadavg
[1] / (double)(1 << SBITS
);
129 avg
[2] = ps_total
.loadavg
[2] / (double)(1 << SBITS
);
133 int uv_fs_event_init(uv_loop_t
* loop
,
134 uv_fs_event_t
* handle
,
135 const char* filename
,
138 loop
->counters
.fs_event_init
++;
139 uv__set_sys_error(loop
, ENOSYS
);
144 void uv__fs_event_close(uv_fs_event_t
* handle
) {
149 char** uv_setup_args(int argc
, char** argv
) {
154 uv_err_t
uv_set_process_title(const char* title
) {
159 uv_err_t
uv_get_process_title(char* buffer
, size_t size
) {
167 uv_err_t
uv_resident_set_memory(size_t* rss
) {
173 (void) snprintf(pp
, sizeof(pp
), "/proc/%lu/psinfo", (unsigned long) getpid());
175 fd
= open(pp
, O_RDONLY
);
177 return uv__new_sys_error(errno
);
181 if (read(fd
, &psinfo
, sizeof(psinfo
)) == sizeof(psinfo
))
182 *rss
= (size_t)psinfo
.pr_rssize
* 1024;
184 err
= uv__new_sys_error(EINVAL
);
192 uv_err_t
uv_uptime(double* uptime
) {
193 struct utmp
*utmp_buf
;
201 while ((utmp_buf
= getutent()) != NULL
) {
202 if (utmp_buf
->ut_user
[0] && utmp_buf
->ut_type
== USER_PROCESS
)
204 if (utmp_buf
->ut_type
== BOOT_TIME
)
205 boot_time
= utmp_buf
->ut_time
;
211 return uv__new_artificial_error(UV_ENOSYS
);
213 *uptime
= time(NULL
) - boot_time
;
218 uv_err_t
uv_cpu_info(uv_cpu_info_t
** cpu_infos
, int* count
) {
219 uv_cpu_info_t
* cpu_info
;
220 perfstat_cpu_total_t ps_total
;
221 perfstat_cpu_t
* ps_cpus
;
222 perfstat_id_t cpu_id
;
223 int result
, ncpus
, idx
= 0;
225 result
= perfstat_cpu_total(NULL
, &ps_total
, sizeof(ps_total
), 1);
227 return uv__new_artificial_error(UV_ENOSYS
);
230 ncpus
= result
= perfstat_cpu(NULL
, NULL
, sizeof(perfstat_cpu_t
), 0);
232 return uv__new_artificial_error(UV_ENOSYS
);
235 ps_cpus
= (perfstat_cpu_t
*) malloc(ncpus
* sizeof(perfstat_cpu_t
));
237 return uv__new_artificial_error(UV_ENOMEM
);
240 strcpy(cpu_id
.name
, FIRST_CPU
);
241 result
= perfstat_cpu(&cpu_id
, ps_cpus
, sizeof(perfstat_cpu_t
), ncpus
);
244 return uv__new_artificial_error(UV_ENOSYS
);
247 *cpu_infos
= (uv_cpu_info_t
*) malloc(ncpus
* sizeof(uv_cpu_info_t
));
250 return uv__new_artificial_error(UV_ENOMEM
);
255 cpu_info
= *cpu_infos
;
256 while (idx
< ncpus
) {
257 cpu_info
->speed
= (int)(ps_total
.processorHZ
/ 1000000);
258 cpu_info
->model
= strdup(ps_total
.description
);
259 cpu_info
->cpu_times
.user
= ps_cpus
[idx
].user
;
260 cpu_info
->cpu_times
.sys
= ps_cpus
[idx
].sys
;
261 cpu_info
->cpu_times
.idle
= ps_cpus
[idx
].idle
;
262 cpu_info
->cpu_times
.irq
= ps_cpus
[idx
].wait
;
263 cpu_info
->cpu_times
.nice
= 0;
273 void uv_free_cpu_info(uv_cpu_info_t
* cpu_infos
, int count
) {
276 for (i
= 0; i
< count
; ++i
) {
277 free(cpu_infos
[i
].model
);
284 uv_err_t
uv_interface_addresses(uv_interface_address_t
** addresses
,
286 uv_interface_address_t
* address
;
287 int sockfd
, size
= 1;
289 struct ifreq
*ifr
, *p
, flg
;
293 if (0 > (sockfd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_IP
))) {
294 return uv__new_artificial_error(UV_ENOSYS
);
297 if (ioctl(sockfd
, SIOCGSIZIFCONF
, &size
) == -1) {
299 return uv__new_artificial_error(UV_ENOSYS
);
302 ifc
.ifc_req
= (struct ifreq
*)malloc(size
);
304 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) == -1) {
306 return uv__new_artificial_error(UV_ENOSYS
);
309 #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
311 /* Count all up and running ipv4/ipv6 addresses */
313 while ((char*)ifr
< (char*)ifc
.ifc_req
+ ifc
.ifc_len
) {
315 ifr
= (struct ifreq
*)
316 ((char*)ifr
+ sizeof(ifr
->ifr_name
) + ADDR_SIZE(ifr
->ifr_addr
));
318 if (!(p
->ifr_addr
.sa_family
== AF_INET6
||
319 p
->ifr_addr
.sa_family
== AF_INET
))
322 memcpy(flg
.ifr_name
, p
->ifr_name
, sizeof(flg
.ifr_name
));
323 if (ioctl(sockfd
, SIOCGIFFLAGS
, &flg
) == -1) {
325 return uv__new_artificial_error(UV_ENOSYS
);
328 if (!(flg
.ifr_flags
& IFF_UP
&& flg
.ifr_flags
& IFF_RUNNING
))
334 /* Alloc the return interface structs */
335 *addresses
= (uv_interface_address_t
*)
336 malloc(*count
* sizeof(uv_interface_address_t
));
339 return uv__new_artificial_error(UV_ENOMEM
);
341 address
= *addresses
;
344 while ((char*)ifr
< (char*)ifc
.ifc_req
+ ifc
.ifc_len
) {
346 ifr
= (struct ifreq
*)
347 ((char*)ifr
+ sizeof(ifr
->ifr_name
) + ADDR_SIZE(ifr
->ifr_addr
));
349 if (!(p
->ifr_addr
.sa_family
== AF_INET6
||
350 p
->ifr_addr
.sa_family
== AF_INET
))
353 memcpy(flg
.ifr_name
, p
->ifr_name
, sizeof(flg
.ifr_name
));
354 if (ioctl(sockfd
, SIOCGIFFLAGS
, &flg
) == -1) {
356 return uv__new_artificial_error(UV_ENOSYS
);
359 if (!(flg
.ifr_flags
& IFF_UP
&& flg
.ifr_flags
& IFF_RUNNING
))
362 /* All conditions above must match count loop */
364 address
->name
= strdup(p
->ifr_name
);
366 if (p
->ifr_addr
.sa_family
== AF_INET6
) {
367 address
->address
.address6
= *((struct sockaddr_in6
*)&p
->ifr_addr
);
369 address
->address
.address4
= *((struct sockaddr_in
*)&p
->ifr_addr
);
372 address
->is_internal
= flg
.ifr_flags
& IFF_LOOPBACK
? 1 : 0;
384 void uv_free_interface_addresses(uv_interface_address_t
* addresses
,
388 for (i
= 0; i
< count
; ++i
) {
389 free(addresses
[i
].name
);