I Have this nice small program which gives me a vector of all alive ip on the network to which system is connected...but works only on windows
std::vector<std::string> resultIPList;
PMIB_IPNET_TABLE2 pipTable = NULL;
unsigned long status = GetIpNetTable2(AF_INET, &pipTable);
if(status != NO_ERROR)
{
LOG_ERROR("Error in getting ip Table")
return resultIPList;
}
for(unsigned i = 0; i < pipTable->NumEntries; i++)
{
char* ip = inet_ntoa(pipTable->Table[i].Address.Ipv4.sin_addr);
std::string str = std::string(ip);
resultIPList.push_back(str);
}
FreeMibTable(pipTable);
pipTable = NULL;
return resultIPList;
is there any way i can do same in Linux (Replacement of GetIpNetTable Function). i am using RHEL
getifaddrs FTW
#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#include <cstdlib>
ifaddrs* pAdapter = NULL;
ifaddrs* pList = NULL;
int result = getifaddrs(&pList);
if (result == -1)
return;
pAdapter = pList;
while (pAdapter)
{
if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_flags & IFF_UP))
{
if (pAdapter->ifa_addr->sa_family == AF_INET)
{
sockaddr_in* addr = (sockaddr_in*)(pAdapter->ifa_addr);
}
else if (pAdapter->ifa_addr->sa_family == AF_INET6)
{
sockaddr_in6* addr6 = (sockaddr_in6*)(pAdapter->ifa_addr);
}
}
pAdapter = pAdapter->ifa_next;
}
freeifaddrs(pList);
pList = NULL;
I would take a look at rtnetlink and getifaddrs on RHEL there is also the NetworkManager all three should allow what you are looking for but I don't think either of the three is a direct replacement for the windows specific API. You will also have to have some way to crach your code so that the relevant functions are compiled. I normally use `#ifndef' to split the code out, that way you can have the same code returning the same things but utilising different code bodies dependant upon the target OS you are compiling for.
I recently answered another question where windows/linux compilation was an issue (for finding the runtime version of boost) here, the principle remains the same and can easily be tailored to your needs.
As an aside I suspect that Boost.Asio may help you out too for a single point of call in both Windows and Linux. You can also get it as an integrated-with-Boost version or as standalone to achieve a smaller footprint.
Let me know how you get on, or if you need any more information :)
Addendum
On Linux you could use something along the lines of:
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
void
print_sockaddr(struct sockaddr* addr,const char *name)
{
char addrbuf[128] ;
addrbuf[0] = 0;
if(addr->sa_family == AF_UNSPEC)
return;
switch(addr->sa_family) {
case AF_INET:
inet_ntop(addr->sa_family,&((struct sockaddr_in*)addr)->sin_addr,addrbuf,sizeof(addrbuf));
break;
case AF_INET6:
inet_ntop(addr->sa_family,&((struct sockaddr_in6*)addr)->sin6_addr,addrbuf,sizeof(addrbuf));
break;
default:
sprintf(addrbuf,"Unknown (%d)",(int)addr->sa_family);
break;
}
printf("%-16s %s\n",name,addrbuf);
}
void
print_ifaddr(struct ifaddrs *addr)
{
char addrbuf[128] ;
addrbuf[0] = 0;
printf("%-24s %s\n","Interface Name:",addr->ifa_name);
if(addr->ifa_addr != NULL)
print_sockaddr(addr->ifa_addr,"Interface Address:");
if(addr->ifa_netmask != NULL)
print_sockaddr(addr->ifa_netmask,"Netmask:");
if(addr->ifa_broadaddr != NULL)
print_sockaddr(addr->ifa_broadaddr,"Broadcast address:");
if(addr->ifa_dstaddr != NULL)
print_sockaddr(addr->ifa_dstaddr,"Peer address:");
puts("");
}
int main(int argc,char *argv[])
{
struct ifaddrs *addrs,*tmp;
if(getifaddrs(&addrs) != 0) {
perror("getifaddrs");
return 1;
}
for(tmp = addrs; tmp ; tmp = tmp->ifa_next) {
print_ifaddr(tmp);
}
freeifaddrs(addrs);
return 0;
}
For other derivatives (Unix, BSD etc) this more basic set of code may be more usefult, though I vaguely remember some problems under BSD (Sorry cant remember what exactly at the moment, think its to do with fail scenarios where certain conditions will render it non-operational)
#include <stdio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#define INT_TO_ADDR(_addr) \
(_addr & 0xFF), \
(_addr >> 8 & 0xFF), \
(_addr >> 16 & 0xFF), \
(_addr >> 24 & 0xFF)
int main()
{
struct ifconf ifc;
struct ifreq ifr[10];
int sd, ifc_num, addr, bcast, mask, network, i;
// Create a socket then use ioctl on the file descriptor to retrieve the interface information.
sd = socket(PF_INET, SOCK_DGRAM, 0);
if (sd > 0)
{
ifc.ifc_len = sizeof(ifr);
ifc.ifc_ifcu.ifcu_buf = (caddr_t)ifr;
if (ioctl(sd, SIOCGIFCONF, &ifc) == 0)
{
ifc_num = ifc.ifc_len / sizeof(struct ifreq);
printf("%d interfaces found.\n", ifc_num);
for (i = 0; i < ifc_num; ++i)
{
if (ifr[i].ifr_addr.sa_family != AF_INET)
{
continue;
}
/* display the interface name */
printf("%d) Interface Name: %s\n", i+1, ifr[i].ifr_name);
/* Retrieve the IP address, broadcast address, and subnet mask. */
if (ioctl(sd, SIOCGIFADDR, &ifr[i]) == 0)
{
addr = ((struct sockaddr_in *)(&ifr[i].ifr_addr))->sin_addr.s_addr;
printf("%d) Interface address: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(addr));
}
if (ioctl(sd, SIOCGIFBRDADDR, &ifr[i]) == 0)
{
bcast = ((struct sockaddr_in *)(&ifr[i].ifr_broadaddr))->sin_addr.s_addr;
printf("%d) Broadcast: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(bcast));
}
if (ioctl(sd, SIOCGIFNETMASK, &ifr[i]) == 0)
{
mask = ((struct sockaddr_in *)(&ifr[i].ifr_netmask))->sin_addr.s_addr;
printf("%d) Netmask: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(mask));
}
/* Compute the current network value from the address and netmask. */
network = addr & mask;
printf("%d) Current Network: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(network));
}
}
close(sd);
}
return 0;
}
Obviously you would need to tailor the code to suit your needs, but perhaps this will help a bit:)
Related
I am trying to get the state of the NumLock key in a platform independent fashion in a C/C++ application. I can get the status using GetKeyState and #defines for the Windows code, but I am having problems with the Unix code (see below).
The code fails with an "Invalid Argument", err code 22 - but I do not understand why. I have tried various different ioctl requests (KDGETLED, KDGKBLED, KDGKBMETA) without success and have run out of ideas.
BTW the only reason for it being two functions was that I was struggling to open the "/dev/..." file and trying different files! This is now fixed (by adding the user to the "input" group - but ideally I would like to avoid this necessity).
#defined (_WIN32)
// Code here works ok
#else
#include <sys/ioctl.h>
#include <sys/kd.h>
#include <sys/vt.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sstream>
int fdKeybd;
int tryStrForInput(std::string &inStr, int *pNumLed)
{
int testVal = -1;
std::string kybdStr = inStr;
printf("\nTry: %s", kybdStr.c_str());
fdKeybd = open(kybdStr.c_str(), O_RDONLY | O_NONBLOCK);
if ( fdKeybd < 0 ) {
printf(" Opening file : Failed. ");
printf ("Error no is : %d ", errno);
printf("Error description is : %s",strerror(errno));
} else {
testVal = ioctl(fdKeybd, KDGKBMETA, pNumLed);
if(testVal != -1) printf(" Success");
else {
printf(" Getting NumLock : Failed. ");
printf ("Error no is : %d ", errno);
printf("Error description is : %s",strerror(errno));
}
}
return testVal;
}
bool isNumlockActivated(void)
{
int NUM_LED = 0x00;
bool bNumLockOn = false;
int testVal = -1;
std::string kybdStr = "/dev/input/by-path/platform-i8042-serio-0-event-kbd";
testVal = tryStrForInput(kybdStr, &NUM_LED);
if(testVal != -1) {
if((NUM_LED == 0x02) || (NUM_LED == 0x03) || (NUM_LED == 0x06) || (NUM_LED == 0x07)) {
bNumLockOn = true;
}
}
close(fdKeybd);
return bNumLockOn;
}
#endif
After much stumbling about in the dark I found the following code works for the Linux side. The reason being I was trying to get the wrong file descriptor (all I actually needed was the standard input) and hence why it did not work.
This posted in case it helps anyone else.
bool isNumlockActivated(void)
{
int fdKeybd = STDIN_FILENO; // Normally 0
int NUM_LED = 0x00;
bool bNumLockOn = false;
int testVal = ioctl(fdKeybd, KDGKBLED, &NUM_LED);
if(testVal == -1) {
printf(" Getting NumLock : Failed. ");
printf ("Error no is : %d ", errno);
printf("Error description is : %s",strerror(errno));
} else {
if((NUM_LED == 0x02) || (NUM_LED == 0x03) || (NUM_LED == 0x06) || (NUM_LED == 0x07)) {
bNumLockOn = true;
}
}
return bNumLockOn;
}
However please note that this is only picking up on the numLock LED state. So if ioctl has been used to control the numLock LED you would have to find the correct key state instead - probably by using a different ioctl request (look at: https://www.tutorialspoint.com/unix_system_calls/ioctl_list.htm)
I'm new to socket programming and wanted to try something simple. This program can manipulate settings on my tv. All messages are 24 bytes. There may be one or more messages returned. I cannot figure out a good solution to get all of the messages without read() blocking on me.
What is below would be what I hoped to be a simple solution. It seems to work in a lot of example code I have found. However, what happens is after the first loop it seems to just block on the read() operation infinitely. If I remove the loop and just put multiple reads, the same thing happens. As long as I don't try to read more information that is sent, I'm ok.
I did try a couple of other things like turning off blocking, and adding a timer. neither worked. At this point I can live with a couple seconds of blocking. I just want the program to exit normally after the read.
adding output for a power_on command. It correctly outputs the two lines it should then blocks indefinitely.
Dans-MBP:~ mreff555$ ./tvthing
24: *SAPOWR0000000000000000
24: *SNPOWR0000000000000001
code below:
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/time.h>
#define PORT 20060
#define POWER_ON "*SCPOWR0000000000000001\n"
#define POWER_OFF "*SCPOWR0000000000000000\n"
#define POWER_STATUS "*SEPOWR################\n"
#define POWER_TOGGLE "*STPOWR################\n"
int main(int argc, char const * argv[])
{
struct sockaddr_in tvAddress;
struct hostent *host = gethostbyname("192.168.1.128");
memset(&tvAddress, 0, sizeof(tvAddress));
tvAddress.sin_family = AF_INET;
tvAddress.sin_addr.s_addr = htonl(INADDR_ANY);
tvAddress.sin_addr.s_addr = ((struct in_addr*)(host->h_addr))->s_addr;
tvAddress.sin_port = htons(PORT);
char sendBuffer[24] = {0};
char recBuffer[24] = {0};
int socket_fd;
if((socket_fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
else
{
if(connect(socket_fd, (struct sockaddr *)&tvAddress, sizeof(struct sockaddr)))
{
perror("connection failed failed");
exit(EXIT_FAILURE);
}
memcpy(&sendBuffer, &POWER_STATUS, sizeof(sendBuffer));
write(socket_fd, sendBuffer, strlen(sendBuffer));
int ret;
while((ret = read(socket_fd, recBuffer, sizeof(recBuffer)) > 0))
{
printf("%d: %s\n", ret, recBuffer);
}
close(socket_fd);
}
}
You need to read until your buffer is full like this:
unsigned readLen = 0;
unsigned totalLen = sizeof(recBuffer);
while (readLen < totalLen) {
int ret = read(socket_fd, recBuffer + readLen, totalLen - readLen);
if (ret > 0) {
readLen += ret;
} else {
// error handling here
break;
}
}
This is needed because read() returns only the currently available amount of bytes which might be less than you have requested. From the corresponding man-page:
RETURN VALUE
On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal.
If you need to receive several responses you can put the described algorithm into a function and use it repeatedly. In any case you need to know how many responses to expect otherwise your read() will block because it seems that your TV's server is programmed to keep the connection open and it is client's responsibility to choose when to disconnect.
If you decide to make your application more sophisticated you can use one of the IO Multiplexing mechanisms to make your wait for response interruptable by timer or terminal input. For example:
while (true) {
pollfd fds[] = {
{ socket_fd, POLLIN, 0 },
{ STDIN_FILENO, POLLIN, 0 }
};
int ret = poll(fds, sizeof(fds) / sizeof(*fds), -1);
if (ret > 0) {
if (fds[0].revents & POLLIN) {
readResponse(); // read and process response
}
if (fds[1].revents & POLLIN) {
break; // exit on terminal input
}
}
}
As it turns out, select is designed exactly for that purpose. It checks the specified file descriptors for a specified time interval, and if successful repeats the process. Tweaking the time interval minimizes the blocking while allowing enough time for additional messages to come in.
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#define PORT 20060
#define POWER_ON "*SCPOWR0000000000000001\n"
#define POWER_OFF "*SCPOWR0000000000000000\n"
#define POWER_STATUS "*SEPOWR################\n"
#define POWER_TOGGLE "*STPOWR################\n"
int main(int argc, char const * argv[])
{
struct sockaddr_in tvAddress;
struct hostent *host = gethostbyname("192.168.1.128");
memset(&tvAddress, 0, sizeof(tvAddress));
tvAddress.sin_family = AF_INET;
tvAddress.sin_addr.s_addr = htonl(INADDR_ANY);
tvAddress.sin_addr.s_addr = ((struct in_addr*)(host->h_addr))->s_addr;
tvAddress.sin_port = htons(PORT);
char sendBuffer[24] = {0};
char recBuffer[24] = {0};
int socket_fd;
if((socket_fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
else
{
if(connect(socket_fd, (struct sockaddr *)&tvAddress, sizeof(struct sockaddr)))
{
perror("connection failed failed");
exit(EXIT_FAILURE);
}
struct timeval tv;
fd_set sockRead;
int selectStatus;
memcpy(&sendBuffer, &POWER_ON, sizeof(sendBuffer));
write(socket_fd, sendBuffer, strlen(sendBuffer));
do
{
FD_ZERO(&sockRead);
FD_SET(socket_fd, &sockRead);
tv.tv_sec = 2;
tv.tv_usec = 500000;
selectStatus = select(socket_fd + 1, &sockRead, NULL, NULL, &tv);
switch(selectStatus)
{
case -1:
perror("select()");
exit(EXIT_FAILURE);
break;
case 0:
break;
default:
printf("Ready for Reading\n");
read(socket_fd, recBuffer, sizeof(recBuffer));
printf("%s\n", recBuffer);
}
}while (selectStatus > 0);
close(socket_fd);
}
}
Given a process id, what is the best way to find the process's creation date-time using C/C++ ?
I'd suggest looking at the top and ps source code (in particular, libtop.c).
I think the following call should be what you need:
int proc_pidbsdinfo(proc_t p, struct proc_bsdinfo *pbsd, int zombie);
From <sys/proc_info.h>:
struct proc_bsdinfo {
...
struct timeval pbi_start;
...
}
Unfortunately there is no public interface for process inspection so the calls are not only version-dependant but also likely to change in future releases.
Here is a simple utility demonstrating how to do this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
int main(int argc, char **argv) {
// Check arguments
if (argc != 2) {
fprintf(stderr,"usage: %s PID\n", argv[0]);
return 1;
}
// Parse and validate PID argument
errno = 0;
char *end = NULL;
long pid = strtol(argv[1], &end, 10);
if (errno != 0 || end == argv[1] || end == NULL || *end != 0 || ((pid_t)pid) != pid) {
fprintf(stderr,"%s: bad PID argument: %s\n", argv[0], argv[1]);
return 1;
}
// Get process info from kernel
struct kinfo_proc info;
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid };
size_t len = sizeof info;
memset(&info,0,len);
int rc = sysctl(mib, (sizeof(mib)/sizeof(int)), &info, &len, NULL, 0);
if (rc != 0) {
fprintf(stderr,"%s: sysctl failed with errno=%d\n", argv[0], errno);
return 1;
}
// Extract start time and confirm process exists
struct timeval tv = info.kp_proc.p_starttime;
if (tv.tv_sec == 0) {
fprintf(stderr,"%s: no such PID %d\n", argv[0], (int)pid);
return 1;
}
// Convert to string - no \n because ctime() result is already \n-terminated
printf("PID %d started at %s", (int)pid, ctime(&(tv.tv_sec)));
return 0;
}
Compile it: clang -o procstart procstart.c
Example of running it:
$ ./procstart $$
PID 37675 started at Sat Apr 9 20:01:55 2022
Note the sysctl API this is calling is undocumented and as such (at least in theory) subject to change at any time. In practice however, it has been rather stable across releases, so while nobody can predict what Apple might do in the future, I think the risk of them breaking this is low.
I am building a client that:
Should be able to recieve information from both the server and the standart input
Should be able to recieve information from the server without asking, for example when another client sends a message.
To do so I tried using select to monitor both possible inputs.
What happens is that when a keyboard input is monitored I send a message to the client and I expect one back, so there's no problem. But when the server sends an unexpected message nothing happens, and I don't know why. Is using select() the proper way to do so? Is it even possible to use select() without listen()ing?
Here's my code (compileable):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#define MAX_CLIENT_NAME 30
#define MAX_TWIT_SIZE 140
#define NUM_OF_ARG 4
#define ERROR -1
#define GREAT_SUCCESS 0
#define OK "OK"
#define EXIT "EXIT"
using std::string;
using std::cerr;
using std::endl;
using std::cout;
string clientName;
int srverfd, numbytes, status, maxSock ;
fd_set inputFdSet; /* Socket file descriptors we want to wake
up for, using select() */
int establishConnection(char * serverAddress,char * port){
if ((srverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return ERROR;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
inet_aton(serverAddress, &server.sin_addr);
server.sin_port = htons(atoi(port));
memset(&(server.sin_zero), '\0', 8);
if (connect(srverfd,(const struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("connect");
close(srverfd);
return ERROR;
}
maxSock = srverfd;
return GREAT_SUCCESS;
}
const char * getUserTweet(){
string temp;
getline(std::cin,temp);
return temp.c_str();
}
void sendMessage(string message){
if ((numbytes = send(srverfd, message.c_str(), message.length(), 0)) == -1) {
perror("sendMessage");
close(srverfd);
}
cout<<"Message sent: "<< message << endl;
return;
}
const char * getMessage(){
char buf[MAX_TWIT_SIZE];
memset(buf,'\0',MAX_TWIT_SIZE);
if ((numbytes = recv(srverfd, buf, 140, 0)) == -1) {
perror("getMessage");
close(srverfd);
}
string temp = buf;
return temp.c_str();
}
void build_select_list() {
FD_ZERO(&inputFdSet);
FD_SET(srverfd,&inputFdSet);
FD_SET(STDIN_FILENO,&inputFdSet);
if (STDIN_FILENO > maxSock)
maxSock = STDIN_FILENO;
return;
}
void readSocket(fd_set tempfd) {
const char * tweet, * inMessage;
if (FD_ISSET(srverfd,&tempfd)) {
inMessage = getMessage();
cout << inMessage << endl;
}
if (FD_ISSET(STDIN_FILENO,&tempfd)) {
tweet = getUserTweet();
sendMessage(tweet);
inMessage = getMessage();
if (strcmp(inMessage,OK) != 0) {
cout << inMessage << endl;
}
if (strcmp(inMessage,EXIT) == 0) {
return;
}
}
return;
}
int main (int argc, char *argv[] ){
int value;
bool clientON = false;
if(establishConnection(argv[2],argv[3])){
cerr << "usage: failed to make connection" << endl << "exiting..." << endl;
exit(EXIT_FAILURE);
}
cout << "Connected successfully" << endl;
sendMessage("CONNECT "+clientName); //Connect
if(strcmp(getMessage(),OK) == 0){
clientON = true;
}
while(clientON){
build_select_list();
value = select(maxSock, &inputFdSet, NULL, NULL, NULL);
if (value < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
continue;
}
else {
readSocket(inputFdSet);
}
}
sendMessage("DISCONNECT");
if(strcmp(getMessage(),OK) == 0){
// do nothing
}
close(srverfd);
return 0;
}
Your select call is invalid. The first parameter must be the highest file descriptor in any of the sets, plus one.
As you have it, an event on srverfd will not "wake up" the select call (unless STDIN_FILENO was somehow less than srverfd, in which case stdin events wouldn't unlock select - but that won't happen in practice).
There are quite a few other problems with your code. (It doesn't really look like C++.)
getUserTweet is unreliable (undefined behavior - temp is destroyed as soon as the function returns, so the char* you return has disappeared by the time its caller will try to use it). Same for getMessage. To remedy that, use std::string everywhere, and only extract the char* when you call into C library functions).
readSocket needlessly copies the FD set (can be expensive).
You should really get rid of all those globals - build one or two classes to encapsulate that state and the networking functions, or something like that.
Certain operations in my app are using more memory than I think they should, and I would like to log the current memory usage to help identify which they are.
Is there a system call that will return the amount of memory currently in use?
The following C function returns the CPU time and resident memory of process pid. To get the resources of other processes, you need root permission. You may also try getrusage(), but I never get it work properly for memory usage. Getting CPU time with getrusage() always works to me.
The function is adapted from the source codes of the ps and top commands. It is part of my program that monitors the memory of other processes.
#ifdef __APPLE__
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/mach_port.h>
#include <mach/mach_traps.h>
#include <mach/task_info.h>
#include <mach/thread_info.h>
#include <mach/thread_act.h>
#include <mach/vm_region.h>
#include <mach/vm_map.h>
#include <mach/task.h>
#include <mach/shared_memory_server.h>
typedef struct vmtotal vmtotal_t;
typedef struct { /* dynamic process information */
size_t rss, vsize;
double utime, stime;
} RunProcDyn;
/* On Mac OS X, the only way to get enough information is to become root. Pretty frustrating!*/
int run_get_dynamic_proc_info(pid_t pid, RunProcDyn *rpd)
{
task_t task;
kern_return_t error;
mach_msg_type_number_t count;
thread_array_t thread_table;
thread_basic_info_t thi;
thread_basic_info_data_t thi_data;
unsigned table_size;
struct task_basic_info ti;
error = task_for_pid(mach_task_self(), pid, &task);
if (error != KERN_SUCCESS) {
/* fprintf(stderr, "++ Probably you have to set suid or become root.\n"); */
rpd->rss = rpd->vsize = 0;
rpd->utime = rpd->stime = 0;
return 0;
}
count = TASK_BASIC_INFO_COUNT;
error = task_info(task, TASK_BASIC_INFO, (task_info_t)&ti, &count);
assert(error == KERN_SUCCESS);
{ /* adapted from ps/tasks.c */
vm_region_basic_info_data_64_t b_info;
vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT;
vm_size_t size;
mach_port_t object_name;
count = VM_REGION_BASIC_INFO_COUNT_64;
error = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO,
(vm_region_info_t)&b_info, &count, &object_name);
if (error == KERN_SUCCESS) {
if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) &&
ti.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE))
{
ti.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
}
}
rpd->rss = ti.resident_size;
rpd->vsize = ti.virtual_size;
}
{ /* calculate CPU times, adapted from top/libtop.c */
unsigned i;
rpd->utime = ti.user_time.seconds + ti.user_time.microseconds * 1e-6;
rpd->stime = ti.system_time.seconds + ti.system_time.microseconds * 1e-6;
error = task_threads(task, &thread_table, &table_size);
assert(error == KERN_SUCCESS);
thi = &thi_data;
for (i = 0; i != table_size; ++i) {
count = THREAD_BASIC_INFO_COUNT;
error = thread_info(thread_table[i], THREAD_BASIC_INFO, (thread_info_t)thi, &count);
assert(error == KERN_SUCCESS);
if ((thi->flags & TH_FLAGS_IDLE) == 0) {
rpd->utime += thi->user_time.seconds + thi->user_time.microseconds * 1e-6;
rpd->stime += thi->system_time.seconds + thi->system_time.microseconds * 1e-6;
}
if (task != mach_task_self()) {
error = mach_port_deallocate(mach_task_self(), thread_table[i]);
assert(error == KERN_SUCCESS);
}
}
error = vm_deallocate(mach_task_self(), (vm_offset_t)thread_table, table_size * sizeof(thread_array_t));
assert(error == KERN_SUCCESS);
}
mach_port_deallocate(mach_task_self(), task);
return 0;
}
#endif /* __APPLE__ */
launch your application with Instruments. put it through the paces, and evaluate the results...
Following #user172818 advice, I tried getrusage and it worked for me:
#include <sys/time.h>
#include <sys/resource.h>
long getMemoryUsage()
{
struct rusage usage;
if(0 == getrusage(RUSAGE_SELF, &usage))
return usage.ru_maxrss; // bytes
else
return 0;
}
I am using Mac OS X 10.9.4, with compiler Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn).
You can give a try to mallocDebug function : http://developer.apple.com/mac/library/DOCUMENTATION/Performance/Conceptual/ManagingMemory/Articles/FindingPatterns.html.