mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-03-11 15:03:56 +00:00
also add test command to report memory usage (RSS on OSX, VMsize on linux, because VMsize on OSX reports all system libraries, so reports about 2GB even for tiny programmes.)
209 lines
5.1 KiB
C
209 lines
5.1 KiB
C
/*
|
|
Serval Distributed Numbering Architecture (DNA)
|
|
Copyright (C) 2010 Paul Gardner-Stephen
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#define __SERVALDNA_OS_INLINE
|
|
#include "os.h"
|
|
#include "str.h"
|
|
#include "log.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <fcntl.h>
|
|
#include <alloca.h>
|
|
#include <dirent.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_MACH_MACH_H
|
|
#include <mach/mach.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_MACH_MACH_H
|
|
|
|
long long memory_footprint()
|
|
{
|
|
struct task_basic_info t_info;
|
|
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
|
|
|
|
if (KERN_SUCCESS != task_info(mach_task_self(),
|
|
TASK_BASIC_INFO, (task_info_t)&t_info,
|
|
&t_info_count))
|
|
{
|
|
return -1;
|
|
}
|
|
return t_info.resident_size/1024LL;
|
|
}
|
|
#else
|
|
long long memory_footprint()
|
|
{
|
|
FILE *f=fopen("/proc/self/status","r");
|
|
if (f) {
|
|
long long kb;
|
|
char line[1024];
|
|
line[0]=0; fgets(line,1024,f);
|
|
while(line[0]) {
|
|
if (sscanf(line,"VmSize: %lld",&kb)==1) {
|
|
fclose(f);
|
|
return kb;
|
|
}
|
|
line[0]=0; fgets(line,1024,f);
|
|
}
|
|
fclose(f);
|
|
return -1;
|
|
} else {
|
|
// no proc file, so just give up
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
int mkdirs(const char *path, mode_t mode)
|
|
{
|
|
return mkdirsn(path, strlen(path), mode);
|
|
}
|
|
|
|
int emkdirs(const char *path, mode_t mode)
|
|
{
|
|
if (mkdirs(path, mode) == -1)
|
|
return WHYF_perror("mkdirs(%s,%o)", alloca_str_toprint(path), mode);
|
|
return 0;
|
|
}
|
|
|
|
int emkdirsn(const char *path, size_t len, mode_t mode)
|
|
{
|
|
if (mkdirsn(path, len, mode) == -1)
|
|
return WHYF_perror("mkdirsn(%s,%lu,%o)", alloca_toprint(-1, path, len), (unsigned long)len, mode);
|
|
return 0;
|
|
}
|
|
|
|
/* This variant must not log anything, because it is used by the logging subsystem itself!
|
|
*
|
|
* @author Andrew Bettison <andrew@servalproject.com>
|
|
*/
|
|
int mkdirsn(const char *path, size_t len, mode_t mode)
|
|
{
|
|
if (len == 0)
|
|
errno = EINVAL;
|
|
else {
|
|
char *pathfrag = alloca(len + 1);
|
|
strncpy(pathfrag, path, len);
|
|
pathfrag[len] = '\0';
|
|
if (mkdir(pathfrag, mode) != -1)
|
|
return 0;
|
|
if (errno == EEXIST) {
|
|
DIR *d = opendir(pathfrag);
|
|
if (d) {
|
|
closedir(d);
|
|
return 0;
|
|
}
|
|
}
|
|
else if (errno == ENOENT) {
|
|
const char *lastsep = path + len - 1;
|
|
while (lastsep != path && *--lastsep != '/')
|
|
;
|
|
while (lastsep != path && *--lastsep == '/')
|
|
;
|
|
if (lastsep != path) {
|
|
if (mkdirsn(path, lastsep - path + 1, mode) == -1)
|
|
return -1;
|
|
if (mkdir(pathfrag, mode) != -1)
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int urandombytes(unsigned char *buf, unsigned long long len)
|
|
{
|
|
static int urandomfd = -1;
|
|
int tries = 0;
|
|
if (urandomfd == -1) {
|
|
for (tries = 0; tries < 4; ++tries) {
|
|
urandomfd = open("/dev/urandom",O_RDONLY);
|
|
if (urandomfd != -1) break;
|
|
sleep(1);
|
|
}
|
|
if (urandomfd == -1) {
|
|
WHY_perror("open(/dev/urandom)");
|
|
return -1;
|
|
}
|
|
}
|
|
tries = 0;
|
|
while (len > 0) {
|
|
int i = (len < 1048576) ? len : 1048576;
|
|
i = read(urandomfd, buf, i);
|
|
if (i == -1) {
|
|
if (++tries > 4) {
|
|
WHY_perror("read(/dev/urandom)");
|
|
if (errno==EBADF) urandomfd=-1;
|
|
return -1;
|
|
}
|
|
} else {
|
|
tries = 0;
|
|
buf += i;
|
|
len -= i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
time_ms_t gettime_ms()
|
|
{
|
|
struct timeval nowtv;
|
|
// If gettimeofday() fails or returns an invalid value, all else is lost!
|
|
if (gettimeofday(&nowtv, NULL) == -1)
|
|
FATAL_perror("gettimeofday");
|
|
if (nowtv.tv_sec < 0 || nowtv.tv_usec < 0 || nowtv.tv_usec >= 1000000)
|
|
FATALF("gettimeofday returned tv_sec=%ld tv_usec=%ld", (long)nowtv.tv_sec, (long)nowtv.tv_usec);
|
|
return nowtv.tv_sec * 1000LL + nowtv.tv_usec / 1000;
|
|
}
|
|
|
|
// Returns sleep time remaining.
|
|
time_ms_t sleep_ms(time_ms_t milliseconds)
|
|
{
|
|
if (milliseconds <= 0)
|
|
return 0;
|
|
struct timespec delay;
|
|
struct timespec remain;
|
|
delay.tv_sec = milliseconds / 1000;
|
|
delay.tv_nsec = (milliseconds % 1000) * 1000000;
|
|
if (nanosleep(&delay, &remain) == -1 && errno != EINTR)
|
|
FATALF_perror("nanosleep(tv_sec=%ld, tv_nsec=%ld)", delay.tv_sec, delay.tv_nsec);
|
|
return remain.tv_sec * 1000 + remain.tv_nsec / 1000000;
|
|
}
|
|
|
|
ssize_t read_symlink(const char *path, char *buf, size_t len)
|
|
{
|
|
if (len == 0) {
|
|
struct stat stat;
|
|
if (lstat(path, &stat) == -1)
|
|
return WHYF_perror("lstat(%s)", path);
|
|
return stat.st_size;
|
|
}
|
|
ssize_t nr = readlink(path, buf, len);
|
|
if (nr == -1)
|
|
return WHYF_perror("readlink(%s)", path);
|
|
if (nr >= len)
|
|
return WHYF("buffer overrun from readlink(%s, len=%lu)", path, (unsigned long) len);
|
|
buf[nr] = '\0';
|
|
return nr;
|
|
}
|