hprof_md.c

Go to the documentation of this file.
00001 /*
00002  * @(#)hprof_md.c 1.31 10/03/23
00003  * 
00004  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  * 
00009  * -Redistribution of source code must retain the above copyright notice, this
00010  *  list of conditions and the following disclaimer.
00011  * 
00012  * -Redistribution in binary form must reproduce the above copyright notice, 
00013  *  this list of conditions and the following disclaimer in the documentation
00014  *  and/or other materials provided with the distribution.
00015  * 
00016  * Neither the name of Oracle or the names of contributors may 
00017  * be used to endorse or promote products derived from this software without 
00018  * specific prior written permission.
00019  * 
00020  * This software is provided "AS IS," without a warranty of any kind. ALL 
00021  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
00022  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
00023  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
00024  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
00025  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
00026  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
00027  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
00028  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
00029  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
00030  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
00031  * 
00032  * You acknowledge that this software is not designed, licensed or intended
00033  * for use in the design, construction, operation or maintenance of any
00034  * nuclear facility.
00035  */
00036 
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <fcntl.h>
00040 
00041 #ifndef LINUX
00042 #include <procfs.h>
00043 #endif
00044 
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <string.h>
00048 #include <sys/socket.h>
00049 #include <sys/errno.h>
00050 #include <unistd.h>
00051 #include <errno.h>
00052 #include <dlfcn.h>
00053 #include <sys/time.h>
00054 
00055 #include <netdb.h>
00056 #include <netinet/in.h>
00057 #include <sys/param.h>
00058 #include <time.h>
00059 
00060 #include "jni.h"
00061 #include "hprof.h"
00062 
00063 #define PATH_SEPARATOR          ":"
00064 #define PATH_SEPARATOR_CHAR     ':'
00065 
00066 int
00067 md_getpid(void)
00068 {
00069     static int pid = -1;
00070     
00071     if ( pid >= 0 ) {
00072   return pid;
00073     }
00074     pid = getpid();
00075     return pid;
00076 }
00077 
00078 void 
00079 md_sleep(unsigned seconds)
00080 {
00081     sleep(seconds);
00082 }
00083 
00084 void
00085 md_init(void)
00086 {
00087 #ifdef LINUX
00088     /* No Hi-Res timer option? */
00089 #else
00090     if ( gdata->micro_state_accounting ) {
00091   char proc_ctl_fn[48];
00092   int  procfd;
00093 
00094   /* Turn on micro state accounting, once per process */
00095   (void)md_snprintf(proc_ctl_fn, sizeof(proc_ctl_fn),
00096     "/proc/%d/ctl", md_getpid());
00097      
00098   procfd = open(proc_ctl_fn, O_WRONLY);
00099   if (procfd >= 0) {
00100       long ctl_op[2];
00101       
00102       ctl_op[0] = PCSET;
00103       ctl_op[1] = PR_MSACCT;
00104       (void)write(procfd, ctl_op, sizeof(ctl_op));
00105       (void)close(procfd);
00106   }
00107     }
00108 #endif
00109 }
00110 
00111 int
00112 md_connect(char *hostname, unsigned short port)
00113 {
00114     struct hostent *hentry;
00115     struct sockaddr_in s;
00116     int fd;
00117 
00118     /* create a socket */
00119     fd = socket(AF_INET, SOCK_STREAM, 0);
00120 
00121     /* find remote host's addr from name */
00122     if ((hentry = gethostbyname(hostname)) == NULL) {
00123   return -1;
00124     }
00125     (void)memset((char *)&s, 0, sizeof(s));
00126     /* set remote host's addr; its already in network byte order */
00127     (void)memcpy(&s.sin_addr.s_addr, *(hentry->h_addr_list),
00128      (int)sizeof(s.sin_addr.s_addr));
00129     /* set remote host's port */
00130     s.sin_port = htons(port);
00131     s.sin_family = AF_INET;
00132 
00133     /* now try connecting */
00134     if (-1 == connect(fd, (struct sockaddr*)&s, sizeof(s))) {
00135   return 0;
00136     }
00137     return fd;
00138 }
00139 
00140 int
00141 md_recv(int f, char *buf, int len, int option)
00142 {
00143     return recv(f, buf, len, option);
00144 }
00145 
00146 int
00147 md_shutdown(int filedes, int option)
00148 {
00149     return shutdown(filedes, option);
00150 }
00151 
00152 int
00153 md_open(const char *filename)
00154 {
00155     return open(filename, O_RDONLY);
00156 }
00157 
00158 int
00159 md_open_binary(const char *filename)
00160 {
00161     return md_open(filename);
00162 }
00163 
00164 int
00165 md_creat(const char *filename)
00166 {
00167     return open(filename, O_WRONLY | O_CREAT | O_TRUNC,
00168       S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
00169 }
00170 
00171 int
00172 md_creat_binary(const char *filename)
00173 {
00174     return md_creat(filename);
00175 }
00176 
00177 jlong
00178 md_seek(int filedes, jlong cur)
00179 {
00180     jlong new_pos;
00181 
00182     if ( cur == (jlong)-1 ) {
00183         new_pos = lseek(filedes, 0, SEEK_END);
00184     } else {
00185         new_pos = lseek(filedes, cur, SEEK_SET);
00186     }
00187     return new_pos;
00188 }
00189 
00190 void
00191 md_close(int filedes)
00192 {
00193     (void)close(filedes);
00194 }
00195 
00196 int 
00197 md_send(int s, const char *msg, int len, int flags)
00198 {
00199     int res;
00200     
00201     do {
00202         res = send(s, msg, len, flags);
00203     } while ((res < 0) && (errno == EINTR));
00204     
00205     return res;
00206 }
00207 
00208 int 
00209 md_write(int filedes, const void *buf, int nbyte)
00210 {
00211     int res;
00212     
00213     do {
00214         res = write(filedes, buf, nbyte);
00215     } while ((res < 0) && (errno == EINTR));
00216 
00217     return res;
00218 }
00219 
00220 int
00221 md_read(int filedes, void *buf, int nbyte)
00222 {
00223     int res;
00224     
00225     do {
00226         res = read(filedes, buf, nbyte);
00227     } while ((res < 0) && (errno == EINTR));
00228 
00229     return res;
00230 }
00231 
00232 /* Time of day in milli-seconds */
00233 static jlong
00234 md_timeofday(void)
00235 {
00236     struct timeval tv;
00237  
00238     if ( gettimeofday(&tv, (void *)0) != 0 ) {
00239   return (jlong)0; /* EOVERFLOW ? */
00240     }
00241     /*LINTED*/
00242     return ((jlong)tv.tv_sec * (jlong)1000) + (jlong)(tv.tv_usec / 1000);
00243 }
00244 
00245 /* Hi-res timer in micro-seconds */
00246 jlong 
00247 md_get_microsecs(void)
00248 {
00249 #ifdef LINUX
00250     return (jlong)(md_timeofday() * (jlong)1000); /* Milli to micro */
00251 #else
00252     return (jlong)(gethrtime()/(hrtime_t)1000); /* Nano seconds to micro seconds */
00253 #endif
00254 }
00255 
00256 /* Time of day in milli-seconds */
00257 jlong 
00258 md_get_timemillis(void)
00259 {
00260     return md_timeofday();
00261 }
00262 
00263 /* Current CPU hi-res CPU time used */
00264 jlong
00265 md_get_thread_cpu_timemillis(void)
00266 {
00267 #ifdef LINUX
00268     return md_timeofday();
00269 #else
00270     return (jlong)(gethrvtime()/1000); /* Nano seconds to milli seconds */
00271 #endif
00272 }
00273 
00274 void 
00275 md_get_prelude_path(char *path, int path_len, char *filename)
00276 {
00277     void *addr;
00278     char libdir[FILENAME_MAX+1];
00279     Dl_info dlinfo;
00280 
00281     libdir[0] = 0;
00282 #ifdef LINUX
00283     addr = (void*)&Agent_OnLoad;
00284 #else
00285     /* Just using &Agent_OnLoad will get the first external symbol with
00286      *   this name in the first .so, which may not be libhprof.so.
00287      *   On Solaris we can actually ask for the address of our Agent_OnLoad.
00288      */
00289     addr = dlsym(RTLD_SELF, "Agent_OnLoad");
00290     /* Just in case the above didn't work (missing linker patch?). */
00291     if ( addr == NULL ) {
00292   addr = (void*)&Agent_OnLoad;
00293     }
00294 #endif
00295 
00296     /* Use dladdr() to get the full path to libhprof.so, which we use to find
00297      *  the prelude file.
00298      */
00299     dlinfo.dli_fname = NULL;
00300     (void)dladdr(addr, &dlinfo);
00301     if ( dlinfo.dli_fname != NULL ) {
00302   char * lastSlash;
00303 
00304   /* Full path to library name, need to move up one directory to 'lib' */
00305   (void)strcpy(libdir, (char *)dlinfo.dli_fname);
00306   lastSlash = strrchr(libdir, '/');
00307   if ( lastSlash != NULL ) {
00308       *lastSlash = '\0';
00309   }
00310   lastSlash = strrchr(libdir, '/');
00311   if ( lastSlash != NULL ) {
00312       *lastSlash = '\0';
00313   }
00314     }
00315     (void)snprintf(path, path_len, "%s/%s", libdir, filename);
00316 }
00317 
00318 
00319 int     
00320 md_vsnprintf(char *s, int n, const char *format, va_list ap)
00321 {
00322     return vsnprintf(s, n, format, ap);
00323 }
00324 
00325 int     
00326 md_snprintf(char *s, int n, const char *format, ...)
00327 {
00328     int ret;
00329     va_list ap;
00330 
00331     va_start(ap, format);
00332     ret = md_vsnprintf(s, n, format, ap);
00333     va_end(ap);
00334     return ret;
00335 }
00336 
00337 void
00338 md_system_error(char *buf, int len)
00339 {
00340     char *p;
00341     
00342     buf[0] = 0;
00343     p = strerror(errno);
00344     if ( p != NULL ) {
00345   (void)strcpy(buf, p);
00346     }
00347 }
00348 
00349 unsigned
00350 md_htons(unsigned short s)
00351 {
00352     return htons(s);
00353 }
00354 
00355 unsigned
00356 md_htonl(unsigned l)
00357 {
00358     return htonl(l);
00359 }
00360 
00361 unsigned  
00362 md_ntohs(unsigned short s)
00363 {
00364     return ntohs(s);
00365 }
00366 
00367 unsigned
00368 md_ntohl(unsigned l)
00369 {
00370     return ntohl(l);
00371 }
00372 
00373 /*
00374  * splits a path, based on its separator, the number of
00375  * elements is returned back in n. 
00376  * It is the callers responsibility to:
00377  *   a> check the value of n, and n may be 0
00378  *   b> ignore any empty path elements
00379  *   c> free up the data.
00380  */
00381 static char** split_path(const char* path, int* n) {
00382     char* inpath;
00383     char** opath;
00384     char* p;
00385     int count = 1;
00386     int i;
00387     
00388     *n = 0;
00389     if (path == NULL || strlen(path) == 0) {
00390         return NULL;
00391     }
00392     inpath = strdup(path);
00393     if (inpath == NULL) {
00394         return NULL;
00395     }
00396     p = strchr(inpath, PATH_SEPARATOR_CHAR);
00397     // get a count of elements to allocate memory
00398     while (p != NULL) {
00399         count++;
00400         p++;
00401         p = strchr(p, PATH_SEPARATOR_CHAR);
00402     }
00403     opath = (char**) calloc(count, sizeof(char*));
00404     if (opath == NULL) {
00405         return NULL;
00406     }
00407 
00408     // do the actual splitting
00409     p = inpath;
00410     for (i = 0 ; i < count ; i++) {
00411         size_t len = strcspn(p, PATH_SEPARATOR);
00412   // allocate the string and add terminator storage
00413         char* s  = (char*)malloc((len + 1)*sizeof(char));
00414         if (s == NULL) {
00415             return NULL;
00416   }
00417         strncpy(s, p, len);
00418   s[len] = '\0';
00419         opath[i] = s;
00420         p += len + 1;
00421     }
00422     free(inpath);
00423     *n = count;
00424     return opath;
00425 }
00426 
00427 /* Create the actual fill filename for a dynamic library.  */
00428 void
00429 md_build_library_name(char *holder, int holderlen, char *pname, char *fname)
00430 {
00431     int n;
00432     int i;
00433     char** pelements;
00434     struct stat statbuf;
00435     const int pnamelen = pname ? strlen(pname) : 0;
00436 
00437     /* Quietly truncate on buffer overflow.  Should be an error. */
00438     if (pnamelen + (int)strlen(fname) + 10 > holderlen) {
00439         *holder = '\0';
00440         return;
00441     }
00442 
00443     /* Construct path to library */
00444     if (pnamelen == 0) {
00445         (void)snprintf(holder, holderlen, "lib%s.so", fname);
00446     } else if (strchr(pname, PATH_SEPARATOR_CHAR) != NULL) {
00447         pelements = split_path(pname, &n);
00448         for (i = 0 ; i < n ; i++) {
00449             // really shouldn't be NULL but what the heck, check can't hurt
00450       if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
00451          continue; // skip the empty path values
00452       }
00453       snprintf(holder, holderlen, "%s/lib%s.so", pelements[i], fname);
00454       if (stat(holder, &statbuf) == 0) {
00455          break;
00456       }
00457         }
00458         // release the storage
00459         for (i = 0 ; i < n ; i++) {
00460             if (pelements[i] != NULL) {
00461                free(pelements[i]);
00462             }
00463         }
00464         if (pelements != NULL) {
00465             free(pelements);
00466         }
00467     } else {
00468         (void)snprintf(holder, holderlen, "%s/lib%s.so", pname, fname);
00469     }
00470 }
00471 
00472 /* Load this library (return NULL on error, and error message in err_buf) */
00473 void *
00474 md_load_library(const char *name, char *err_buf, int err_buflen)
00475 {
00476     void * result;
00477     
00478     result = dlopen(name, RTLD_LAZY);
00479     if (result == NULL) {
00480   (void)strncpy(err_buf, dlerror(), err_buflen-2);
00481   err_buf[err_buflen-1] = '\0';
00482     }
00483     return result;
00484 }
00485 
00486 /* Unload this library */
00487 void 
00488 md_unload_library(void *handle)
00489 {
00490     (void)dlclose(handle);
00491 }
00492 
00493 /* Find an entry point inside this library (return NULL if not found) */
00494 void * 
00495 md_find_library_entry(void *handle, const char *name)
00496 {
00497     void * sym;
00498     
00499     sym =  dlsym(handle, name);
00500     return sym;
00501 }
00502 

Generated on 19 Nov 2012 for hprof by  doxygen 1.6.1