/* * Command line: opannotate /usr/freeswitch/lib/libapr-1.so.0.2.7 --source=/usr/src/freeswitch.trunk/libs/apr-1.2.7/ * * Interpretation of command line: * Output annotated source file with samples * Output all files * * CPU: AMD64 processors, speed 1991.58 MHz (estimated) * Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No unit mask) count 100000 */ /* * Total samples for file : "strings/apr_snprintf.c" * * 8 25.8065 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr.h" :#include "apr_private.h" : :#include "apr_lib.h" :#include "apr_strings.h" :#include "apr_network_io.h" :#include "apr_portable.h" :#include :#if APR_HAVE_CTYPE_H :#include :#endif :#if APR_HAVE_NETINET_IN_H :#include :#endif :#if APR_HAVE_SYS_SOCKET_H :#include :#endif :#if APR_HAVE_ARPA_INET_H :#include :#endif :#if APR_HAVE_LIMITS_H :#include :#endif :#if APR_HAVE_STRING_H :#include :#endif : :typedef enum { : NO = 0, YES = 1 :} boolean_e; : :#ifndef FALSE :#define FALSE 0 :#endif :#ifndef TRUE :#define TRUE 1 :#endif :#define NUL '\0' :#define WIDE_INT long : :typedef WIDE_INT wide_int; :typedef unsigned WIDE_INT u_wide_int; :typedef apr_int64_t widest_int; :#ifdef __TANDEM :/* Although Tandem supports "long long" there is no unsigned variant. */ :typedef unsigned long u_widest_int; :#else :typedef apr_uint64_t u_widest_int; :#endif :typedef int bool_int; : :#define S_NULL "(null)" :#define S_NULL_LEN 6 : :#define FLOAT_DIGITS 6 :#define EXPONENT_LENGTH 10 : :/* : * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions : * : * NOTICE: this is a magic number; do not decrease it : */ :#define NUM_BUF_SIZE 512 : :/* : * cvt.c - IEEE floating point formatting routines for FreeBSD : * from GNU libc-4.6.27. Modified to be thread safe. : */ : :/* : * apr_ecvt converts to decimal : * the number of digits is specified by ndigit : * decpt is set to the position of the decimal point : * sign is set to 0 for positive, 1 for negative : */ : :#define NDIG 80 : :/* buf must have at least NDIG bytes */ :static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, : int eflag, char *buf) :{ : register int r2; : double fi, fj; : register char *p, *p1; : : if (ndigits >= NDIG - 1) : ndigits = NDIG - 2; : r2 = 0; : *sign = 0; : p = &buf[0]; : if (arg < 0) { : *sign = 1; : arg = -arg; : } : arg = modf(arg, &fi); : p1 = &buf[NDIG]; : /* : * Do integer part : */ : if (fi != 0) { : p1 = &buf[NDIG]; : while (p1 > &buf[0] && fi != 0) { : fj = modf(fi / 10, &fi); : *--p1 = (int) ((fj + .03) * 10) + '0'; : r2++; : } : while (p1 < &buf[NDIG]) : *p++ = *p1++; : } : else if (arg > 0) { : while ((fj = arg * 10) < 1) { : arg = fj; : r2--; : } : } : p1 = &buf[ndigits]; : if (eflag == 0) : p1 += r2; : if (p1 < &buf[0]) { : *decpt = -ndigits; : buf[0] = '\0'; : return (buf); : } : *decpt = r2; : while (p <= p1 && p < &buf[NDIG]) { : arg *= 10; : arg = modf(arg, &fj); : *p++ = (int) fj + '0'; : } : if (p1 >= &buf[NDIG]) { : buf[NDIG - 1] = '\0'; : return (buf); : } : p = p1; : *p1 += 5; : while (*p1 > '9') { : *p1 = '0'; : if (p1 > buf) : ++ * --p1; : else { : *p1 = '1'; : (*decpt)++; : if (eflag == 0) { : if (p > buf) : *p = '0'; : p++; : } : } : } : *p = '\0'; : return (buf); :} : :static char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) :{ : return (apr_cvt(arg, ndigits, decpt, sign, 1, buf)); :} : :static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) :{ : return (apr_cvt(arg, ndigits, decpt, sign, 0, buf)); :} : :/* : * apr_gcvt - Floating output conversion to : * minimal length string : */ : :static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform) :{ : int sign, decpt; : register char *p1, *p2; : register int i; : char buf1[NDIG]; : : p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1); : p2 = buf; : if (sign) : *p2++ = '-'; : for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) : ndigit--; : if ((decpt >= 0 && decpt - ndigit > 4) : || (decpt < 0 && decpt < -3)) { /* use E-style */ : decpt--; : *p2++ = *p1++; : *p2++ = '.'; : for (i = 1; i < ndigit; i++) : *p2++ = *p1++; : *p2++ = 'e'; : if (decpt < 0) { : decpt = -decpt; : *p2++ = '-'; : } : else : *p2++ = '+'; : if (decpt / 100 > 0) : *p2++ = decpt / 100 + '0'; : if (decpt / 10 > 0) : *p2++ = (decpt % 100) / 10 + '0'; : *p2++ = decpt % 10 + '0'; : } : else { : if (decpt <= 0) { : if (*p1 != '0') : *p2++ = '.'; : while (decpt < 0) { : decpt++; : *p2++ = '0'; : } : } : for (i = 1; i <= ndigit; i++) { : *p2++ = *p1++; : if (i == decpt) : *p2++ = '.'; : } : if (ndigit < decpt) { : while (ndigit++ < decpt) : *p2++ = '0'; : *p2++ = '.'; : } : } : if (p2[-1] == '.' && !altform) : p2--; : *p2 = '\0'; : return (buf); :} : :/* : * The INS_CHAR macro inserts a character in the buffer and writes : * the buffer back to disk if necessary : * It uses the char pointers sp and bep: : * sp points to the next available character in the buffer : * bep points to the end-of-buffer+1 : * While using this macro, note that the nextb pointer is NOT updated. : * : * NOTE: Evaluation of the c argument should not have any side-effects : */ :#define INS_CHAR(c, sp, bep, cc) \ :{ \ : if (sp) { \ : if (sp >= bep) { \ : vbuff->curpos = sp; \ : if (flush_func(vbuff)) \ : return -1; \ : sp = vbuff->curpos; \ : bep = vbuff->endpos; \ : } \ : *sp++ = (c); \ : } \ : cc++; \ :} : :#define NUM(c) (c - '0') : :#define STR_TO_DEC(str, num) \ : num = NUM(*str++); \ : while (apr_isdigit(*str)) \ : { \ : num *= 10 ; \ : num += NUM(*str++); \ : } : :/* : * This macro does zero padding so that the precision : * requirement is satisfied. The padding is done by : * adding '0's to the left of the string that is going : * to be printed. We don't allow precision to be large : * enough that we continue past the start of s. : * : * NOTE: this makes use of the magic info that s is : * always based on num_buf with a size of NUM_BUF_SIZE. : */ :#define FIX_PRECISION(adjust, precision, s, s_len) \ : if (adjust) { \ : apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \ : ? precision : NUM_BUF_SIZE - 1; \ : while (s_len < p) \ : { \ : *--s = '0'; \ : s_len++; \ : } \ : } : :/* : * Macro that does padding. The padding is done by printing : * the character ch. : */ :#define PAD(width, len, ch) \ :do \ :{ \ : INS_CHAR(ch, sp, bep, cc); \ : width--; \ :} \ :while (width > len) : :/* : * Prefix the character ch to the string str : * Increase length : * Set the has_prefix flag : */ :#define PREFIX(str, length, ch) \ : *--str = ch; \ : length++; \ : has_prefix=YES; : : :/* : * Convert num to its decimal format. : * Return value: : * - a pointer to a string containing the number (no sign) : * - len contains the length of the string : * - is_negative is set to TRUE or FALSE depending on the sign : * of the number (always set to FALSE if is_unsigned is TRUE) : * : * The caller provides a buffer for the string: that is the buf_end argument : * which is a pointer to the END of the buffer + 1 (i.e. if the buffer : * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) : * : * Note: we have 2 versions. One is used when we need to use quads : * (conv_10_quad), the other when we don't (conv_10). We're assuming the : * latter is faster. : */ :static char *conv_10(register wide_int num, register bool_int is_unsigned, : register bool_int *is_negative, char *buf_end, : register apr_size_t *len) :{ : register char *p = buf_end; : register u_wide_int magnitude; : : if (is_unsigned) { : magnitude = (u_wide_int) num; : *is_negative = FALSE; : } : else { : *is_negative = (num < 0); : : /* : * On a 2's complement machine, negating the most negative integer : * results in a number that cannot be represented as a signed integer. : * Here is what we do to obtain the number's magnitude: : * a. add 1 to the number : * b. negate it (becomes positive) : * c. convert it to unsigned : * d. add 1 : */ : if (*is_negative) { : wide_int t = num + 1; : : magnitude = ((u_wide_int) -t) + 1; : } : else : magnitude = (u_wide_int) num; : } : : /* : * We use a do-while loop so that we write at least 1 digit : */ : do { : register u_wide_int new_magnitude = magnitude / 10; : : *--p = (char) (magnitude - new_magnitude * 10 + '0'); : magnitude = new_magnitude; : } : while (magnitude); : : *len = buf_end - p; : return (p); :} : :static char *conv_10_quad(widest_int num, register bool_int is_unsigned, : register bool_int *is_negative, char *buf_end, : register apr_size_t *len) :{ : register char *p = buf_end; : u_widest_int magnitude; : : /* : * We see if we can use the faster non-quad version by checking the : * number against the largest long value it can be. If <=, we : * punt to the quicker version. : */ : if ((num <= ULONG_MAX && is_unsigned) : || (num <= LONG_MAX && num >= LONG_MIN && !is_unsigned)) : return(conv_10( (wide_int)num, is_unsigned, is_negative, : buf_end, len)); : : if (is_unsigned) { : magnitude = (u_widest_int) num; : *is_negative = FALSE; : } : else { : *is_negative = (num < 0); : : /* : * On a 2's complement machine, negating the most negative integer : * results in a number that cannot be represented as a signed integer. : * Here is what we do to obtain the number's magnitude: : * a. add 1 to the number : * b. negate it (becomes positive) : * c. convert it to unsigned : * d. add 1 : */ : if (*is_negative) { : widest_int t = num + 1; : : magnitude = ((u_widest_int) -t) + 1; : } : else : magnitude = (u_widest_int) num; : } : : /* : * We use a do-while loop so that we write at least 1 digit : */ : do { : u_widest_int new_magnitude = magnitude / 10; : : *--p = (char) (magnitude - new_magnitude * 10 + '0'); : magnitude = new_magnitude; : } : while (magnitude); : : *len = buf_end - p; : return (p); :} : : : :static char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len) :{ : unsigned addr = ntohl(ia->s_addr); : char *p = buf_end; : bool_int is_negative; : apr_size_t sub_len; : : p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); : *--p = '.'; : p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); : *--p = '.'; : p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); : *--p = '.'; : p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); : : *len = buf_end - p; : return (p); :} : : : :static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len) :{ : char *p = buf_end; : bool_int is_negative; : apr_size_t sub_len; : char *ipaddr_str; : : p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len); : *--p = ':'; : apr_sockaddr_ip_get(&ipaddr_str, sa); : sub_len = strlen(ipaddr_str); :#if APR_HAVE_IPV6 : if (sa->family == APR_INET6 && : !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) { : *(p - 1) = ']'; : p -= sub_len + 2; : *p = '['; : memcpy(p + 1, ipaddr_str, sub_len); : } : else :#endif : { : p -= sub_len; : memcpy(p, ipaddr_str, sub_len); : } : : *len = buf_end - p; : return (p); :} : : : :#if APR_HAS_THREADS :static char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) :{ : union { : apr_os_thread_t tid; : apr_uint64_t alignme; : } u; : int is_negative; : : u.tid = *tid; : switch(sizeof(u.tid)) { : case sizeof(apr_int32_t): : return conv_10(*(apr_uint32_t *)&u.tid, TRUE, &is_negative, buf_end, len); : case sizeof(apr_int64_t): : return conv_10_quad(*(apr_uint64_t *)&u.tid, TRUE, &is_negative, buf_end, len); : default: : /* not implemented; stick 0 in the buffer */ : return conv_10(0, TRUE, &is_negative, buf_end, len); : } :} :#endif : : : :/* : * Convert a floating point number to a string formats 'f', 'e' or 'E'. : * The result is placed in buf, and len denotes the length of the string : * The sign is returned in the is_negative argument (and is not placed : * in buf). : */ :static char *conv_fp(register char format, register double num, : boolean_e add_dp, int precision, bool_int *is_negative, : char *buf, apr_size_t *len) :{ : register char *s = buf; : register char *p; : int decimal_point; : char buf1[NDIG]; : : if (format == 'f') : p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1); : else /* either e or E format */ : p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); : : /* : * Check for Infinity and NaN : */ : if (apr_isalpha(*p)) { : *len = strlen(p); : memcpy(buf, p, *len + 1); : *is_negative = FALSE; : return (buf); : } : : if (format == 'f') { : if (decimal_point <= 0) { : *s++ = '0'; : if (precision > 0) { : *s++ = '.'; : while (decimal_point++ < 0) : *s++ = '0'; : } : else if (add_dp) : *s++ = '.'; : } : else { : while (decimal_point-- > 0) : *s++ = *p++; : if (precision > 0 || add_dp) : *s++ = '.'; : } : } : else { : *s++ = *p++; : if (precision > 0 || add_dp) : *s++ = '.'; : } : : /* : * copy the rest of p, the NUL is NOT copied : */ : while (*p) : *s++ = *p++; : : if (format != 'f') { : char temp[EXPONENT_LENGTH]; /* for exponent conversion */ : apr_size_t t_len; : bool_int exponent_is_negative; : : *s++ = format; /* either e or E */ : decimal_point--; : if (decimal_point != 0) { : p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, : &temp[EXPONENT_LENGTH], &t_len); : *s++ = exponent_is_negative ? '-' : '+'; : : /* : * Make sure the exponent has at least 2 digits : */ : if (t_len == 1) : *s++ = '0'; : while (t_len--) : *s++ = *p++; : } : else { : *s++ = '+'; : *s++ = '0'; : *s++ = '0'; : } : } : : *len = s - buf; : return (buf); :} : : :/* : * Convert num to a base X number where X is a power of 2. nbits determines X. : * For example, if nbits is 3, we do base 8 conversion : * Return value: : * a pointer to a string containing the number : * : * The caller provides a buffer for the string: that is the buf_end argument : * which is a pointer to the END of the buffer + 1 (i.e. if the buffer : * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) : * : * As with conv_10, we have a faster version which is used when : * the number isn't quad size. : */ :static char *conv_p2(register u_wide_int num, register int nbits, : char format, char *buf_end, register apr_size_t *len) :{ : register int mask = (1 << nbits) - 1; : register char *p = buf_end; : static const char low_digits[] = "0123456789abcdef"; : static const char upper_digits[] = "0123456789ABCDEF"; : register const char *digits = (format == 'X') ? upper_digits : low_digits; : : do { : *--p = digits[num & mask]; : num >>= nbits; : } : while (num); : : *len = buf_end - p; : return (p); :} : :static char *conv_p2_quad(u_widest_int num, register int nbits, : char format, char *buf_end, register apr_size_t *len) :{ : register int mask = (1 << nbits) - 1; : register char *p = buf_end; : static const char low_digits[] = "0123456789abcdef"; : static const char upper_digits[] = "0123456789ABCDEF"; : register const char *digits = (format == 'X') ? upper_digits : low_digits; : : if (num <= ULONG_MAX) : return(conv_p2((u_wide_int)num, nbits, format, buf_end, len)); : : do { : *--p = digits[num & mask]; : num >>= nbits; : } : while (num); : : *len = buf_end - p; : return (p); :} : :#if APR_HAS_THREADS :static char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) :{ : union { : apr_os_thread_t tid; : apr_uint64_t alignme; : } u; : int is_negative; : : u.tid = *tid; : switch(sizeof(u.tid)) { : case sizeof(apr_int32_t): : return conv_p2(*(apr_uint32_t *)&u.tid, 4, 'x', buf_end, len); : case sizeof(apr_int64_t): : return conv_p2_quad(*(apr_uint64_t *)&u.tid, 4, 'x', buf_end, len); : default: : /* not implemented; stick 0 in the buffer */ : return conv_10(0, TRUE, &is_negative, buf_end, len); : } :} :#endif : :/* : * Do format conversion placing the output in buffer : */ :APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), : apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap) 2 6.4516 :{ /* apr_vformatter total: 7 22.5806 */ : register char *sp; : register char *bep; : register int cc = 0; : register apr_size_t i; : : register char *s = NULL; : char *q; : apr_size_t s_len; : : register apr_size_t min_width = 0; : apr_size_t precision = 0; : enum { : LEFT, RIGHT : } adjust; : char pad_char; : char prefix_char; : : double fp_num; : widest_int i_quad = (widest_int) 0; : u_widest_int ui_quad; : wide_int i_num = (wide_int) 0; : u_wide_int ui_num; : : char num_buf[NUM_BUF_SIZE]; : char char_buf[2]; /* for printing %% and % */ : : enum var_type_enum { : IS_QUAD, IS_LONG, IS_SHORT, IS_INT : }; : enum var_type_enum var_type = IS_INT; : : /* : * Flag variables : */ : boolean_e alternate_form; : boolean_e print_sign; : boolean_e print_blank; : boolean_e adjust_precision; : boolean_e adjust_width; : bool_int is_negative; : : sp = vbuff->curpos; : bep = vbuff->endpos; : : while (*fmt) { 1 3.2258 : if (*fmt != '%') { : INS_CHAR(*fmt, sp, bep, cc); : } : else { : /* : * Default variable settings : */ : boolean_e print_something = YES; : adjust = RIGHT; : alternate_form = print_sign = print_blank = NO; : pad_char = ' '; : prefix_char = NUL; : : fmt++; : : /* : * Try to avoid checking for flags, width or precision : */ 1 3.2258 : if (!apr_islower(*fmt)) { : /* : * Recognize flags: -, #, BLANK, + : */ : for (;; fmt++) { : if (*fmt == '-') : adjust = LEFT; : else if (*fmt == '+') : print_sign = YES; : else if (*fmt == '#') : alternate_form = YES; : else if (*fmt == ' ') : print_blank = YES; : else if (*fmt == '0') : pad_char = '0'; : else : break; : } : : /* : * Check if a width was specified : */ : if (apr_isdigit(*fmt)) { : STR_TO_DEC(fmt, min_width); : adjust_width = YES; : } : else if (*fmt == '*') { : int v = va_arg(ap, int); : fmt++; : adjust_width = YES; : if (v < 0) { : adjust = LEFT; : min_width = (apr_size_t)(-v); : } : else : min_width = (apr_size_t)v; : } : else : adjust_width = NO; : : /* : * Check if a precision was specified : */ : if (*fmt == '.') { : adjust_precision = YES; : fmt++; : if (apr_isdigit(*fmt)) { : STR_TO_DEC(fmt, precision); : } : else if (*fmt == '*') { : int v = va_arg(ap, int); : fmt++; : precision = (v < 0) ? 0 : (apr_size_t)v; : } : else : precision = 0; : } : else : adjust_precision = NO; : } : else : adjust_precision = adjust_width = NO; : : /* : * Modifier check. Note that if APR_INT64_T_FMT is "d", : * the first if condition is never true. : */ : if ((sizeof(APR_INT64_T_FMT) == 4 && : fmt[0] == APR_INT64_T_FMT[0] && : fmt[1] == APR_INT64_T_FMT[1]) || : (sizeof(APR_INT64_T_FMT) == 3 && : fmt[0] == APR_INT64_T_FMT[0]) || : (sizeof(APR_INT64_T_FMT) > 4 && : strncmp(fmt, APR_INT64_T_FMT, : sizeof(APR_INT64_T_FMT) - 2) == 0)) { : /* Need to account for trailing 'd' and null in sizeof() */ : var_type = IS_QUAD; : fmt += (sizeof(APR_INT64_T_FMT) - 2); : } : else if (*fmt == 'q') { : var_type = IS_QUAD; : fmt++; : } : else if (*fmt == 'l') { : var_type = IS_LONG; : fmt++; : } : else if (*fmt == 'h') { : var_type = IS_SHORT; : fmt++; : } : else { : var_type = IS_INT; : } : : /* : * Argument extraction and printing. : * First we determine the argument type. : * Then, we convert the argument to a string. : * On exit from the switch, s points to the string that : * must be printed, s_len has the length of the string : * The precision requirements, if any, are reflected in s_len. : * : * NOTE: pad_char may be set to '0' because of the 0 flag. : * It is reset to ' ' by non-numeric formats : */ : switch (*fmt) { : case 'u': : if (var_type == IS_QUAD) { : i_quad = va_arg(ap, u_widest_int); : s = conv_10_quad(i_quad, 1, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { : if (var_type == IS_LONG) : i_num = (wide_int) va_arg(ap, u_wide_int); : else if (var_type == IS_SHORT) : i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int); : else : i_num = (wide_int) va_arg(ap, unsigned int); : s = conv_10(i_num, 1, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : break; : : case 'd': : case 'i': : if (var_type == IS_QUAD) { : i_quad = va_arg(ap, widest_int); : s = conv_10_quad(i_quad, 0, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { : if (var_type == IS_LONG) : i_num = (wide_int) va_arg(ap, wide_int); : else if (var_type == IS_SHORT) : i_num = (wide_int) (short) va_arg(ap, int); : else : i_num = (wide_int) va_arg(ap, int); : s = conv_10(i_num, 0, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : : if (is_negative) : prefix_char = '-'; : else if (print_sign) : prefix_char = '+'; : else if (print_blank) : prefix_char = ' '; : break; : : : case 'o': : if (var_type == IS_QUAD) { : ui_quad = va_arg(ap, u_widest_int); : s = conv_p2_quad(ui_quad, 3, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { : if (var_type == IS_LONG) : ui_num = (u_wide_int) va_arg(ap, u_wide_int); : else if (var_type == IS_SHORT) : ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); : else : ui_num = (u_wide_int) va_arg(ap, unsigned int); : s = conv_p2(ui_num, 3, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : if (alternate_form && *s != '0') { : *--s = '0'; : s_len++; : } : break; : : : case 'x': : case 'X': : if (var_type == IS_QUAD) { : ui_quad = va_arg(ap, u_widest_int); : s = conv_p2_quad(ui_quad, 4, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { : if (var_type == IS_LONG) : ui_num = (u_wide_int) va_arg(ap, u_wide_int); : else if (var_type == IS_SHORT) : ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); : else : ui_num = (u_wide_int) va_arg(ap, unsigned int); : s = conv_p2(ui_num, 4, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : if (alternate_form && i_num != 0) { : *--s = *fmt; /* 'x' or 'X' */ : *--s = '0'; : s_len += 2; : } : break; : : : case 's': 1 3.2258 : s = va_arg(ap, char *); : if (s != NULL) { : if (!adjust_precision) { : s_len = strlen(s); : } : else { : /* From the C library standard in section 7.9.6.1: : * ...if the precision is specified, no more then : * that many characters are written. If the : * precision is not specified or is greater : * than the size of the array, the array shall : * contain a null character. : * : * My reading is is precision is specified and : * is less then or equal to the size of the : * array, no null character is required. So : * we can't do a strlen. : * : * This figures out the length of the string : * up to the precision. Once it's long enough : * for the specified precision, we don't care : * anymore. : * : * NOTE: you must do the length comparison : * before the check for the null character. : * Otherwise, you'll check one beyond the : * last valid character. : */ : const char *walk; : : for (walk = s, s_len = 0; : (s_len < precision) && (*walk != '\0'); : ++walk, ++s_len); : } : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : break; : : : case 'f': : case 'e': : case 'E': : fp_num = va_arg(ap, double); : /* : * We use &num_buf[ 1 ], so that we have room for the sign : */ : s = NULL; :#ifdef HAVE_ISNAN : if (isnan(fp_num)) { : s = "nan"; : s_len = 3; : } :#endif :#ifdef HAVE_ISINF : if (!s && isinf(fp_num)) { : s = "inf"; : s_len = 3; : } :#endif : if (!s) { : s = conv_fp(*fmt, fp_num, alternate_form, : (adjust_precision == NO) ? FLOAT_DIGITS : precision, : &is_negative, &num_buf[1], &s_len); : if (is_negative) : prefix_char = '-'; : else if (print_sign) : prefix_char = '+'; : else if (print_blank) : prefix_char = ' '; : } : break; : : : case 'g': : case 'G': : if (adjust_precision == NO) : precision = FLOAT_DIGITS; : else if (precision == 0) : precision = 1; : /* : * * We use &num_buf[ 1 ], so that we have room for the sign : */ : s = apr_gcvt(va_arg(ap, double), precision, &num_buf[1], : alternate_form); : if (*s == '-') : prefix_char = *s++; : else if (print_sign) : prefix_char = '+'; : else if (print_blank) : prefix_char = ' '; : : s_len = strlen(s); : : if (alternate_form && (q = strchr(s, '.')) == NULL) { : s[s_len++] = '.'; : s[s_len] = '\0'; /* delimit for following strchr() */ : } : if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) : *q = 'E'; : break; : : : case 'c': : char_buf[0] = (char) (va_arg(ap, int)); : s = &char_buf[0]; : s_len = 1; : pad_char = ' '; : break; : : : case '%': : char_buf[0] = '%'; : s = &char_buf[0]; : s_len = 1; : pad_char = ' '; : break; : : : case 'n': : if (var_type == IS_QUAD) : *(va_arg(ap, widest_int *)) = cc; : else if (var_type == IS_LONG) : *(va_arg(ap, long *)) = cc; : else if (var_type == IS_SHORT) : *(va_arg(ap, short *)) = cc; : else : *(va_arg(ap, int *)) = cc; : print_something = NO; : break; : : /* : * This is where we extend the printf format, with a second : * type specifier : */ : case 'p': : switch(*++fmt) { : /* : * If the pointer size is equal to or smaller than the size : * of the largest unsigned int, we convert the pointer to a : * hex number, otherwise we print "%p" to indicate that we : * don't handle "%p". : */ : case 'p': :#ifdef APR_VOID_P_IS_QUAD : if (sizeof(void *) <= sizeof(u_widest_int)) { : ui_quad = (u_widest_int) va_arg(ap, void *); : s = conv_p2_quad(ui_quad, 4, 'x', : &num_buf[NUM_BUF_SIZE], &s_len); : } :#else : if (sizeof(void *) <= sizeof(u_wide_int)) { : ui_num = (u_wide_int) va_arg(ap, void *); : s = conv_p2(ui_num, 4, 'x', : &num_buf[NUM_BUF_SIZE], &s_len); : } :#endif : else { : s = "%p"; : s_len = 2; : prefix_char = NUL; : } : pad_char = ' '; : break; : : /* print an apr_sockaddr_t as a.b.c.d:port */ : case 'I': : { : apr_sockaddr_t *sa; : : sa = va_arg(ap, apr_sockaddr_t *); : if (sa != NULL) { : s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } : break; : : /* print a struct in_addr as a.b.c.d */ : case 'A': : { : struct in_addr *ia; : : ia = va_arg(ap, struct in_addr *); : if (ia != NULL) { : s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } : break; : : case 'T': :#if APR_HAS_THREADS : { : apr_os_thread_t *tid; : : tid = va_arg(ap, apr_os_thread_t *); : if (tid != NULL) { : s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } :#else : char_buf[0] = '0'; : s = &char_buf[0]; : s_len = 1; : pad_char = ' '; :#endif : break; : : case 't': :#if APR_HAS_THREADS : { : apr_os_thread_t *tid; : : tid = va_arg(ap, apr_os_thread_t *); : if (tid != NULL) { : s = conv_os_thread_t_hex(tid, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } :#else : char_buf[0] = '0'; : s = &char_buf[0]; : s_len = 1; : pad_char = ' '; :#endif : break; : : case NUL: : /* if %p ends the string, oh well ignore it */ : continue; : : default: : s = "bogus %p"; : s_len = 8; : prefix_char = NUL; : (void)va_arg(ap, void *); /* skip the bogus argument on the stack */ : break; : } : break; : : case NUL: : /* : * The last character of the format string was %. : * We ignore it. : */ : continue; : : : /* : * The default case is for unrecognized %'s. : * We print % to help the user identify what : * option is not understood. : * This is also useful in case the user wants to pass : * the output of format_converter to another function : * that understands some other % (like syslog). : * Note that we can't point s inside fmt because the : * unknown could be preceded by width etc. : */ : default: : char_buf[0] = '%'; : char_buf[1] = *fmt; : s = char_buf; : s_len = 2; : pad_char = ' '; : break; : } : : if (prefix_char != NUL && s != S_NULL && s != char_buf) { : *--s = prefix_char; : s_len++; : } : : if (adjust_width && adjust == RIGHT && min_width > s_len) { : if (pad_char == '0' && prefix_char != NUL) { : INS_CHAR(*s, sp, bep, cc); : s++; : s_len--; : min_width--; : } : PAD(min_width, s_len, pad_char); : } : : /* : * Print the string s. : */ : if (print_something == YES) { : for (i = s_len; i != 0; i--) { 1 3.2258 : INS_CHAR(*s, sp, bep, cc); : s++; : } : } : 1 3.2258 : if (adjust_width && adjust == LEFT && min_width > s_len) : PAD(min_width, s_len, pad_char); : } : fmt++; : } : vbuff->curpos = sp; : : return cc; :} : : :static int snprintf_flush(apr_vformatter_buff_t *vbuff) :{ : /* if the buffer fills we have to abort immediately, there is no way : * to "flush" an apr_snprintf... there's nowhere to flush it to. : */ : return -1; :} : : :APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, : const char *format, ...) 1 3.2258 :{ /* apr_snprintf total: 1 3.2258 */ : int cc; : va_list ap; : apr_vformatter_buff_t vbuff; : : if (len == 0) { : /* NOTE: This is a special case; we just want to return the number : * of chars that would be written (minus \0) if the buffer : * size was infinite. We leverage the fact that INS_CHAR : * just does actual inserts iff the buffer pointer is non-NULL. : * In this case, we don't care what buf is; it can be NULL, since : * we don't touch it at all. : */ : vbuff.curpos = NULL; : vbuff.endpos = NULL; : } else { : /* save one byte for nul terminator */ : vbuff.curpos = buf; : vbuff.endpos = buf + len - 1; : } : va_start(ap, format); : cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); : va_end(ap); : if (len != 0) { : *vbuff.curpos = '\0'; : } : return (cc == -1) ? (int)len : cc; :} : : :APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, : va_list ap) :{ : int cc; : apr_vformatter_buff_t vbuff; : : if (len == 0) { : /* See above note */ : vbuff.curpos = NULL; : vbuff.endpos = NULL; : } else { : /* save one byte for nul terminator */ : vbuff.curpos = buf; : vbuff.endpos = buf + len - 1; : } : cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); : if (len != 0) { : *vbuff.curpos = '\0'; : } : return (cc == -1) ? (int)len : cc; :} /* * Total samples for file : "memory/unix/apr_pools.c" * * 5 16.1290 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr.h" :#include "apr_private.h" : :#include "apr_atomic.h" :#include "apr_portable.h" /* for get_os_proc */ :#include "apr_strings.h" :#include "apr_general.h" :#include "apr_pools.h" :#include "apr_allocator.h" :#include "apr_lib.h" :#include "apr_thread_mutex.h" :#include "apr_hash.h" :#include "apr_time.h" :#define APR_WANT_MEMFUNC :#include "apr_want.h" :#include "apr_env.h" : :#if APR_HAVE_STDLIB_H :#include /* for malloc, free and abort */ :#endif : :#if APR_HAVE_UNISTD_H :#include /* for getpid */ :#endif : : :/* : * Magic numbers : */ : :#define MIN_ALLOC 8192 :#define MAX_INDEX 20 : :#define BOUNDARY_INDEX 12 :#define BOUNDARY_SIZE (1 << BOUNDARY_INDEX) : :/* : * Timing constants for killing subprocesses : * There is a total 3-second delay between sending a SIGINT : * and sending of the final SIGKILL. : * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64 : * for the exponetial timeout alogrithm. : */ :#define TIMEOUT_USECS 3000000 :#define TIMEOUT_INTERVAL 46875 : :/* : * Allocator : */ : :struct apr_allocator_t { : apr_uint32_t max_index; : apr_uint32_t max_free_index; : apr_uint32_t current_free_index; :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; :#endif /* APR_HAS_THREADS */ : apr_pool_t *owner; : apr_memnode_t *free[MAX_INDEX]; :}; : :#define SIZEOF_ALLOCATOR_T APR_ALIGN_DEFAULT(sizeof(apr_allocator_t)) : : :/* : * Allocator : */ : :APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator) :{ : apr_allocator_t *new_allocator; : : *allocator = NULL; : : if ((new_allocator = malloc(SIZEOF_ALLOCATOR_T)) == NULL) : return APR_ENOMEM; : : memset(new_allocator, 0, SIZEOF_ALLOCATOR_T); : new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED; : : *allocator = new_allocator; : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator) :{ /* apr_allocator_destroy total: 1 3.2258 */ : apr_uint32_t index; : apr_memnode_t *node, **ref; : : for (index = 0; index < MAX_INDEX; index++) { : ref = &allocator->free[index]; : while ((node = *ref) != NULL) { 1 3.2258 : *ref = node->next; : free(node); : } : } : : free(allocator); :} : :#if APR_HAS_THREADS :APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator, : apr_thread_mutex_t *mutex) :{ : allocator->mutex = mutex; :} : :APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get( : apr_allocator_t *allocator) :{ : return allocator->mutex; :} :#endif /* APR_HAS_THREADS */ : :APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator, : apr_pool_t *pool) :{ : allocator->owner = pool; :} : :APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator) :{ : return allocator->owner; :} : :APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator, : apr_size_t in_size) :{ : apr_uint32_t max_free_index; : apr_uint32_t size = (APR_UINT32_TRUNC_CAST)in_size; : :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : mutex = apr_allocator_mutex_get(allocator); : if (mutex != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : max_free_index = APR_ALIGN(size, BOUNDARY_SIZE) >> BOUNDARY_INDEX; : allocator->current_free_index += max_free_index; : allocator->current_free_index -= allocator->max_free_index; : allocator->max_free_index = max_free_index; : if (allocator->current_free_index > max_free_index) : allocator->current_free_index = max_free_index; : :#if APR_HAS_THREADS : if (mutex != NULL) : apr_thread_mutex_unlock(mutex); :#endif :} : :static APR_INLINE :apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t size) :{ : apr_memnode_t *node, **ref; : apr_uint32_t max_index; : apr_size_t i, index; : : /* Round up the block size to the next boundary, but always : * allocate at least a certain size (MIN_ALLOC). : */ : size = APR_ALIGN(size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE); : if (size < MIN_ALLOC) : size = MIN_ALLOC; : : /* Find the index for this node size by : * dividing its size by the boundary size : */ : index = (size >> BOUNDARY_INDEX) - 1; : : if (index > APR_UINT32_MAX) { : return NULL; : } : : /* First see if there are any nodes in the area we know : * our node will fit into. : */ : if (index <= allocator->max_index) { :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_lock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : /* Walk the free list to see if there are : * any nodes on it of the requested size : * : * NOTE: an optimization would be to check : * allocator->free[index] first and if no : * node is present, directly use : * allocator->free[max_index]. This seems : * like overkill though and could cause : * memory waste. : */ : max_index = allocator->max_index; : ref = &allocator->free[index]; : i = index; : while (*ref == NULL && i < max_index) { : ref++; : i++; : } : : if ((node = *ref) != NULL) { : /* If we have found a node and it doesn't have any : * nodes waiting in line behind it _and_ we are on : * the highest available index, find the new highest : * available index : */ : if ((*ref = node->next) == NULL && i >= max_index) { : do { : ref--; : max_index--; : } : while (*ref == NULL && max_index > 0); : : allocator->max_index = max_index; : } : : allocator->current_free_index += node->index; : if (allocator->current_free_index > allocator->max_free_index) : allocator->current_free_index = allocator->max_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : node->next = NULL; : node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; : : return node; : } : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : } : : /* If we found nothing, seek the sink (at index 0), if : * it is not empty. : */ : else if (allocator->free[0]) { :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_lock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : /* Walk the free list to see if there are : * any nodes on it of the requested size : */ : ref = &allocator->free[0]; : while ((node = *ref) != NULL && index > node->index) : ref = &node->next; : : if (node) { : *ref = node->next; : : allocator->current_free_index += node->index; : if (allocator->current_free_index > allocator->max_free_index) : allocator->current_free_index = allocator->max_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : node->next = NULL; : node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; : : return node; : } : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : } : : /* If we haven't got a suitable node, malloc a new one : * and initialize it. : */ : if ((node = malloc(size)) == NULL) : return NULL; : : node->next = NULL; : node->index = (APR_UINT32_TRUNC_CAST)index; : node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; : node->endp = (char *)node + size; : : return node; :} : :static APR_INLINE :void allocator_free(apr_allocator_t *allocator, apr_memnode_t *node) :{ : apr_memnode_t *next, *freelist = NULL; : apr_uint32_t index, max_index; : apr_uint32_t max_free_index, current_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_lock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : max_index = allocator->max_index; : max_free_index = allocator->max_free_index; : current_free_index = allocator->current_free_index; : : /* Walk the list of submitted nodes and free them one by one, : * shoving them in the right 'size' buckets as we go. : */ : do { : next = node->next; : index = node->index; : : if (max_free_index != APR_ALLOCATOR_MAX_FREE_UNLIMITED : && index > current_free_index) { : node->next = freelist; : freelist = node; : } : else if (index < MAX_INDEX) { : /* Add the node to the appropiate 'size' bucket. Adjust : * the max_index when appropiate. : */ : if ((node->next = allocator->free[index]) == NULL : && index > max_index) { : max_index = index; : } : allocator->free[index] = node; : current_free_index -= index; : } : else { : /* This node is too large to keep in a specific size bucket, : * just add it to the sink (at index 0). : */ : node->next = allocator->free[0]; : allocator->free[0] = node; : current_free_index -= index; : } : } while ((node = next) != NULL); : : allocator->max_index = max_index; : allocator->current_free_index = current_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : while (freelist != NULL) { : node = freelist; : freelist = node->next; : free(node); : } :} : :APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator, : apr_size_t size) :{ : return allocator_alloc(allocator, size); :} : :APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator, : apr_memnode_t *node) :{ : allocator_free(allocator, node); :} : : : :/* : * Debug level : */ : :#define APR_POOL_DEBUG_GENERAL 0x01 :#define APR_POOL_DEBUG_VERBOSE 0x02 :#define APR_POOL_DEBUG_LIFETIME 0x04 :#define APR_POOL_DEBUG_OWNER 0x08 :#define APR_POOL_DEBUG_VERBOSE_ALLOC 0x10 : :#define APR_POOL_DEBUG_VERBOSE_ALL (APR_POOL_DEBUG_VERBOSE \ : | APR_POOL_DEBUG_VERBOSE_ALLOC) : : :/* : * Structures : */ : :typedef struct cleanup_t cleanup_t; : :/** A list of processes */ :struct process_chain { : /** The process ID */ : apr_proc_t *proc; : apr_kill_conditions_e kill_how; : /** The next process in the list */ : struct process_chain *next; :}; : : :#if APR_POOL_DEBUG : :typedef struct debug_node_t debug_node_t; : :struct debug_node_t { : debug_node_t *next; : apr_uint32_t index; : void *beginp[64]; : void *endp[64]; :}; : :#define SIZEOF_DEBUG_NODE_T APR_ALIGN_DEFAULT(sizeof(debug_node_t)) : :#endif /* APR_POOL_DEBUG */ : :/* The ref field in the apr_pool_t struct holds a : * pointer to the pointer referencing this pool. : * It is used for parent, child, sibling management. : * Look at apr_pool_create_ex() and apr_pool_destroy() : * to see how it is used. : */ :struct apr_pool_t { : apr_pool_t *parent; : apr_pool_t *child; : apr_pool_t *sibling; : apr_pool_t **ref; : cleanup_t *cleanups; : cleanup_t *free_cleanups; : apr_allocator_t *allocator; : struct process_chain *subprocesses; : apr_abortfunc_t abort_fn; : apr_hash_t *user_data; : const char *tag; : :#if !APR_POOL_DEBUG : apr_memnode_t *active; : apr_memnode_t *self; /* The node containing the pool itself */ : char *self_first_avail; : :#else /* APR_POOL_DEBUG */ : apr_pool_t *joined; /* the caller has guaranteed that this pool : * will survive as long as ->joined */ : debug_node_t *nodes; : const char *file_line; : apr_uint32_t creation_flags; : unsigned int stat_alloc; : unsigned int stat_total_alloc; : unsigned int stat_clear; :#if APR_HAS_THREADS : apr_os_thread_t owner; : apr_thread_mutex_t *mutex; :#endif /* APR_HAS_THREADS */ :#endif /* APR_POOL_DEBUG */ :#ifdef NETWARE : apr_os_proc_t owner_proc; :#endif /* defined(NETWARE) */ :}; : :#define SIZEOF_POOL_T APR_ALIGN_DEFAULT(sizeof(apr_pool_t)) : : :/* : * Variables : */ : :static apr_byte_t apr_pools_initialized = 0; :static apr_pool_t *global_pool = NULL; : :#if !APR_POOL_DEBUG :static apr_allocator_t *global_allocator = NULL; :#endif /* !APR_POOL_DEBUG */ : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) :static apr_file_t *file_stderr = NULL; :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : :/* : * Local functions : */ : :static void run_cleanups(cleanup_t **c); :static void run_child_cleanups(cleanup_t **c); :static void free_proc_chain(struct process_chain *procs); : :#if APR_POOL_DEBUG :static void pool_destroy_debug(apr_pool_t *pool, const char *file_line); :#endif : :#if !APR_POOL_DEBUG :/* : * Initialization : */ : :APR_DECLARE(apr_status_t) apr_pool_initialize(void) :{ : apr_status_t rv; : : if (apr_pools_initialized++) : return APR_SUCCESS; : : if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) { : apr_pools_initialized = 0; : return rv; : } : : if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, : global_allocator)) != APR_SUCCESS) { : apr_allocator_destroy(global_allocator); : global_allocator = NULL; : apr_pools_initialized = 0; : return rv; : } : : apr_pool_tag(global_pool, "apr_global_pool"); : : /* This has to happen here because mutexes might be backed by : * atomics. It used to be snug and safe in apr_initialize(). : */ : if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { : return rv; : } : :#if APR_HAS_THREADS : { : apr_thread_mutex_t *mutex; : : if ((rv = apr_thread_mutex_create(&mutex, : APR_THREAD_MUTEX_DEFAULT, : global_pool)) != APR_SUCCESS) { : return rv; : } : : apr_allocator_mutex_set(global_allocator, mutex); : } :#endif /* APR_HAS_THREADS */ : : apr_allocator_owner_set(global_allocator, global_pool); : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_pool_terminate(void) :{ : if (!apr_pools_initialized) : return; : : if (--apr_pools_initialized) : return; : : apr_pool_destroy(global_pool); /* This will also destroy the mutex */ : global_pool = NULL; : : global_allocator = NULL; :} : : :/* Node list management helper macros; list_insert() inserts 'node' : * before 'point'. */ :#define list_insert(node, point) do { \ : node->ref = point->ref; \ : *node->ref = node; \ : node->next = point; \ : point->ref = &node->next; \ :} while (0) : :/* list_remove() removes 'node' from its list. */ :#define list_remove(node) do { \ : *node->ref = node->next; \ : node->next->ref = node->ref; \ :} while (0) : :/* : * Memory allocation : */ : :APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size) 1 3.2258 :{ /* apr_palloc total: 1 3.2258 */ : apr_memnode_t *active, *node; : void *mem; : apr_size_t free_index; : : size = APR_ALIGN_DEFAULT(size); : active = pool->active; : : /* If the active node has enough bytes left, use it. */ : if (size < (apr_size_t)(active->endp - active->first_avail)) { : mem = active->first_avail; : active->first_avail += size; : : return mem; : } : : node = active->next; : if (size < (apr_size_t)(node->endp - node->first_avail)) { : list_remove(node); : } : else { : if ((node = allocator_alloc(pool->allocator, size)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : } : : node->free_index = 0; : : mem = node->first_avail; : node->first_avail += size; : : list_insert(node, active); : : pool->active = node; : : free_index = (APR_ALIGN(active->endp - active->first_avail + 1, : BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; : : active->free_index = (APR_UINT32_TRUNC_CAST)free_index; : node = active->next; : if (free_index >= node->free_index) : return mem; : : do { : node = node->next; : } : while (free_index < node->free_index); : : list_remove(active); : list_insert(active, node); : : return mem; :} : :/* Provide an implementation of apr_pcalloc for backward compatibility : * with code built before apr_pcalloc was a macro : */ : :#ifdef apr_pcalloc :#undef apr_pcalloc :#endif : :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size); :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size) :{ : void *mem; : : size = APR_ALIGN_DEFAULT(size); : if ((mem = apr_palloc(pool, size)) != NULL) { : memset(mem, 0, size); : } : : return mem; :} : : :/* : * Pool creation/destruction : */ : :APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool) :{ : apr_memnode_t *active; : : /* Destroy the subpools. The subpools will detach themselves from : * this pool thus this loop is safe and easy. : */ : while (pool->child) : apr_pool_destroy(pool->child); : : /* Run cleanups */ : run_cleanups(&pool->cleanups); : pool->cleanups = NULL; : pool->free_cleanups = NULL; : : /* Free subprocesses */ : free_proc_chain(pool->subprocesses); : pool->subprocesses = NULL; : : /* Clear the user data. */ : pool->user_data = NULL; : : /* Find the node attached to the pool structure, reset it, make : * it the active node and free the rest of the nodes. : */ : active = pool->active = pool->self; : active->first_avail = pool->self_first_avail; : : if (active->next == active) : return; : : *active->ref = NULL; : allocator_free(pool->allocator, active->next); : active->next = active; : active->ref = &active->next; :} : :APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool) :{ : apr_memnode_t *active; : apr_allocator_t *allocator; : : /* Destroy the subpools. The subpools will detach themselve from : * this pool thus this loop is safe and easy. : */ : while (pool->child) : apr_pool_destroy(pool->child); : : /* Run cleanups */ : run_cleanups(&pool->cleanups); : : /* Free subprocesses */ : free_proc_chain(pool->subprocesses); : : /* Remove the pool from the parents child list */ : if (pool->parent) { :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : if ((*pool->ref = pool->sibling) != NULL) : pool->sibling->ref = pool->ref; : :#if APR_HAS_THREADS : if (mutex) : apr_thread_mutex_unlock(mutex); :#endif /* APR_HAS_THREADS */ : } : : /* Find the block attached to the pool structure. Save a copy of the : * allocator pointer, because the pool struct soon will be no more. : */ : allocator = pool->allocator; : active = pool->self; : *active->ref = NULL; : :#if APR_HAS_THREADS : if (apr_allocator_owner_get(allocator) == pool) { : /* Make sure to remove the lock, since it is highly likely to : * be invalid now. : */ : apr_allocator_mutex_set(allocator, NULL); : } :#endif /* APR_HAS_THREADS */ : : /* Free all the nodes in the pool (including the node holding the : * pool struct), by giving them back to the allocator. : */ : allocator_free(allocator, active); : : /* If this pool happens to be the owner of the allocator, free : * everything in the allocator (that includes the pool struct : * and the allocator). Don't worry about destroying the optional mutex : * in the allocator, it will have been destroyed by the cleanup function. : */ : if (apr_allocator_owner_get(allocator) == pool) { : apr_allocator_destroy(allocator); : } :} : :APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator) :{ : apr_pool_t *pool; : apr_memnode_t *node; : : *newpool = NULL; : : if (!parent) : parent = global_pool; : : if (!abort_fn && parent) : abort_fn = parent->abort_fn; : : if (allocator == NULL) : allocator = parent->allocator; : : if ((node = allocator_alloc(allocator, : MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) { : if (abort_fn) : abort_fn(APR_ENOMEM); : : return APR_ENOMEM; : } : : node->next = node; : node->ref = &node->next; : : pool = (apr_pool_t *)node->first_avail; : node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T; : : pool->allocator = allocator; : pool->active = pool->self = node; : pool->abort_fn = abort_fn; : pool->child = NULL; : pool->cleanups = NULL; : pool->free_cleanups = NULL; : pool->subprocesses = NULL; : pool->user_data = NULL; : pool->tag = NULL; : :#ifdef NETWARE : pool->owner_proc = (apr_os_proc_t)getnlmhandle(); :#endif /* defined(NETWARE) */ : : if ((pool->parent = parent) != NULL) { :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : if ((pool->sibling = parent->child) != NULL) : pool->sibling->ref = &pool->sibling; : : parent->child = pool; : pool->ref = &parent->child; : :#if APR_HAS_THREADS : if (mutex) : apr_thread_mutex_unlock(mutex); :#endif /* APR_HAS_THREADS */ : } : else { : pool->sibling = NULL; : pool->ref = NULL; : } : : *newpool = pool; : : return APR_SUCCESS; :} : : :/* : * "Print" functions : */ : :/* : * apr_psprintf is implemented by writing directly into the current : * block of the pool, starting right at first_avail. If there's : * insufficient room, then a new block is allocated and the earlier : * output is copied over. The new block isn't linked into the pool : * until all the output is done. : * : * Note that this is completely safe because nothing else can : * allocate in this apr_pool_t while apr_psprintf is running. alarms are : * blocked, and the only thing outside of apr_pools.c that's invoked : * is apr_vformatter -- which was purposefully written to be : * self-contained with no callouts. : */ : :struct psprintf_data { : apr_vformatter_buff_t vbuff; : apr_memnode_t *node; : apr_pool_t *pool; : apr_byte_t got_a_new_node; : apr_memnode_t *free; :}; : :#define APR_PSPRINTF_MIN_STRINGSIZE 32 : :static int psprintf_flush(apr_vformatter_buff_t *vbuff) :{ : struct psprintf_data *ps = (struct psprintf_data *)vbuff; : apr_memnode_t *node, *active; : apr_size_t cur_len, size; : char *strp; : apr_pool_t *pool; : apr_size_t free_index; : : pool = ps->pool; : active = ps->node; : strp = ps->vbuff.curpos; : cur_len = strp - active->first_avail; : size = cur_len << 1; : : /* Make sure that we don't try to use a block that has less : * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it. This : * also catches the case where size == 0, which would result : * in reusing a block that can't even hold the NUL byte. : */ : if (size < APR_PSPRINTF_MIN_STRINGSIZE) : size = APR_PSPRINTF_MIN_STRINGSIZE; : : node = active->next; : if (!ps->got_a_new_node : && size < (apr_size_t)(node->endp - node->first_avail)) { : : list_remove(node); : list_insert(node, active); : : node->free_index = 0; : : pool->active = node; : : free_index = (APR_ALIGN(active->endp - active->first_avail + 1, : BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; : : active->free_index = (APR_UINT32_TRUNC_CAST)free_index; : node = active->next; : if (free_index < node->free_index) { : do { : node = node->next; : } : while (free_index < node->free_index); : : list_remove(active); : list_insert(active, node); : } : : node = pool->active; : } : else { : if ((node = allocator_alloc(pool->allocator, size)) == NULL) : return -1; : : if (ps->got_a_new_node) { : active->next = ps->free; : ps->free = active; : } : : ps->got_a_new_node = 1; : } : : memcpy(node->first_avail, active->first_avail, cur_len); : : ps->node = node; : ps->vbuff.curpos = node->first_avail + cur_len; : ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */ : : return 0; :} : :APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) :{ : struct psprintf_data ps; : char *strp; : apr_size_t size; : apr_memnode_t *active, *node; : apr_size_t free_index; : : ps.node = active = pool->active; : ps.pool = pool; : ps.vbuff.curpos = ps.node->first_avail; : : /* Save a byte for the NUL terminator */ : ps.vbuff.endpos = ps.node->endp - 1; : ps.got_a_new_node = 0; : ps.free = NULL; : : /* Make sure that the first node passed to apr_vformatter has at least : * room to hold the NUL terminator. : */ : if (ps.node->first_avail == ps.node->endp) { : if (psprintf_flush(&ps.vbuff) == -1) { : if (pool->abort_fn) { : pool->abort_fn(APR_ENOMEM); : } : : return NULL; : } : } : : if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : strp = ps.vbuff.curpos; : *strp++ = '\0'; : : size = strp - ps.node->first_avail; : size = APR_ALIGN_DEFAULT(size); : strp = ps.node->first_avail; : ps.node->first_avail += size; : : if (ps.free) : allocator_free(pool->allocator, ps.free); : : /* : * Link the node in if it's a new one : */ : if (!ps.got_a_new_node) : return strp; : : active = pool->active; : node = ps.node; : : node->free_index = 0; : : list_insert(node, active); : : pool->active = node; : : free_index = (APR_ALIGN(active->endp - active->first_avail + 1, : BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; : : active->free_index = (APR_UINT32_TRUNC_CAST)free_index; : node = active->next; : : if (free_index >= node->free_index) : return strp; : : do { : node = node->next; : } : while (free_index < node->free_index); : : list_remove(active); : list_insert(active, node); : : return strp; :} : : :#else /* APR_POOL_DEBUG */ :/* : * Debug helper functions : */ : : :/* : * Walk the pool tree rooted at pool, depth first. When fn returns : * anything other than 0, abort the traversal and return the value : * returned by fn. : */ :static int apr_pool_walk_tree(apr_pool_t *pool, : int (*fn)(apr_pool_t *pool, void *data), : void *data) :{ : int rv; : apr_pool_t *child; : : rv = fn(pool, data); : if (rv) : return rv; : :#if APR_HAS_THREADS : if (pool->mutex) { : apr_thread_mutex_lock(pool->mutex); : } :#endif /* APR_HAS_THREADS */ : : child = pool->child; : while (child) { : rv = apr_pool_walk_tree(child, fn, data); : if (rv) : break; : : child = child->sibling; : } : :#if APR_HAS_THREADS : if (pool->mutex) { : apr_thread_mutex_unlock(pool->mutex); : } :#endif /* APR_HAS_THREADS */ : : return rv; :} : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) :static void apr_pool_log_event(apr_pool_t *pool, const char *event, : const char *file_line, int deref) :{ : if (file_stderr) { : if (deref) { : apr_file_printf(file_stderr, : "POOL DEBUG: " : "[%lu" :#if APR_HAS_THREADS : "/%lu" :#endif /* APR_HAS_THREADS */ : "] " : "%7s " : "(%10lu/%10lu/%10lu) " : "0x%08X \"%s\" " : "<%s> " : "(%u/%u/%u) " : "\n", : (unsigned long)getpid(), :#if APR_HAS_THREADS : (unsigned long)apr_os_thread_current(), :#endif /* APR_HAS_THREADS */ : event, : (unsigned long)apr_pool_num_bytes(pool, 0), : (unsigned long)apr_pool_num_bytes(pool, 1), : (unsigned long)apr_pool_num_bytes(global_pool, 1), : (unsigned int)pool, pool->tag, : file_line, : pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear); : } : else { : apr_file_printf(file_stderr, : "POOL DEBUG: " : "[%lu" :#if APR_HAS_THREADS : "/%lu" :#endif /* APR_HAS_THREADS */ : "] " : "%7s " : " " : "0x%08X " : "<%s> " : "\n", : (unsigned long)getpid(), :#if APR_HAS_THREADS : (unsigned long)apr_os_thread_current(), :#endif /* APR_HAS_THREADS */ : event, : (unsigned int)pool, : file_line); : } : } :} :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) :static int pool_is_child_of(apr_pool_t *parent, void *data) :{ : apr_pool_t *pool = (apr_pool_t *)data; : : return (pool == parent); :} : :static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent) :{ : if (parent == NULL) : return 0; : : return apr_pool_walk_tree(parent, pool_is_child_of, pool); :} :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ : :static void apr_pool_check_integrity(apr_pool_t *pool) :{ : /* Rule of thumb: use of the global pool is always : * ok, since the only user is apr_pools.c. Unless : * people have searched for the top level parent and : * started to use that... : */ : if (pool == global_pool || global_pool == NULL) : return; : : /* Lifetime : * This basically checks to see if the pool being used is still : * a relative to the global pool. If not it was previously : * destroyed, in which case we abort(). : */ :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) : if (!apr_pool_is_child_of(pool, global_pool)) { :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : apr_pool_log_event(pool, "LIFE", : __FILE__ ":apr_pool_integrity check", 0); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : abort(); : } :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) :#if APR_HAS_THREADS : if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) { :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : apr_pool_log_event(pool, "THREAD", : __FILE__ ":apr_pool_integrity check", 0); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : abort(); : } :#endif /* APR_HAS_THREADS */ :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */ :} : : :/* : * Initialization (debug) : */ : :APR_DECLARE(apr_status_t) apr_pool_initialize(void) :{ : apr_status_t rv; :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : char *logpath; :#endif : : if (apr_pools_initialized++) : return APR_SUCCESS; : : /* Since the debug code works a bit differently then the : * regular pools code, we ask for a lock here. The regular : * pools code has got this lock embedded in the global : * allocator, a concept unknown to debug mode. : */ : if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, : NULL)) != APR_SUCCESS) { : return rv; : } : : apr_pool_tag(global_pool, "APR global pool"); : : apr_pools_initialized = 1; : : /* This has to happen here because mutexes might be backed by : * atomics. It used to be snug and safe in apr_initialize(). : */ : if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { : return rv; : } : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : rv = apr_env_get(&logpath, "APR_POOL_DEBUG_LOG", global_pool); : : if (rv == APR_SUCCESS) { : apr_file_open(&file_stderr, logpath, APR_APPEND|APR_WRITE|APR_CREATE, : APR_OS_DEFAULT, global_pool); : } : else { : apr_file_open_stderr(&file_stderr, global_pool); : } : : if (file_stderr) { : apr_file_printf(file_stderr, : "POOL DEBUG: [PID" :#if APR_HAS_THREADS : "/TID" :#endif /* APR_HAS_THREADS */ : "] ACTION (SIZE /POOL SIZE /TOTAL SIZE) " : "POOL \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n"); : : apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0); : } :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_pool_terminate(void) :{ : if (!apr_pools_initialized) : return; : : apr_pools_initialized = 0; : : apr_pool_destroy(global_pool); /* This will also destroy the mutex */ : global_pool = NULL; : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : file_stderr = NULL; :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ :} : : :/* : * Memory allocation (debug) : */ : :static void *pool_alloc(apr_pool_t *pool, apr_size_t size) :{ : debug_node_t *node; : void *mem; : : if ((mem = malloc(size)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : node = pool->nodes; : if (node == NULL || node->index == 64) { : if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : memset(node, 0, SIZEOF_DEBUG_NODE_T); : : node->next = pool->nodes; : pool->nodes = node; : node->index = 0; : } : : node->beginp[node->index] = mem; : node->endp[node->index] = (char *)mem + size; : node->index++; : : pool->stat_alloc++; : pool->stat_total_alloc++; : : return mem; :} : :APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : void *mem; : : apr_pool_check_integrity(pool); : : mem = pool_alloc(pool, size); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) : apr_pool_log_event(pool, "PALLOC", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ : : return mem; :} : :APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : void *mem; : : apr_pool_check_integrity(pool); : : mem = pool_alloc(pool, size); : memset(mem, 0, size); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) : apr_pool_log_event(pool, "PCALLOC", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ : : return mem; :} : : :/* : * Pool creation/destruction (debug) : */ : :#define POOL_POISON_BYTE 'A' : :static void pool_clear_debug(apr_pool_t *pool, const char *file_line) :{ : debug_node_t *node; : apr_uint32_t index; : : /* Destroy the subpools. The subpools will detach themselves from : * this pool thus this loop is safe and easy. : */ : while (pool->child) : pool_destroy_debug(pool->child, file_line); : : /* Run cleanups */ : run_cleanups(&pool->cleanups); : pool->free_cleanups = NULL; : pool->cleanups = NULL; : : /* If new child pools showed up, this is a reason to raise a flag */ : if (pool->child) : abort(); : : /* Free subprocesses */ : free_proc_chain(pool->subprocesses); : pool->subprocesses = NULL; : : /* Clear the user data. */ : pool->user_data = NULL; : : /* Free the blocks, scribbling over them first to help highlight : * use-after-free issues. */ : while ((node = pool->nodes) != NULL) { : pool->nodes = node->next; : : for (index = 0; index < node->index; index++) { : memset(node->beginp[index], POOL_POISON_BYTE, : node->endp[index] - node->beginp[index]); : free(node->beginp[index]); : } : : memset(node, POOL_POISON_BYTE, SIZEOF_DEBUG_NODE_T); : free(node); : } : : pool->stat_alloc = 0; : pool->stat_clear++; :} : :APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool, : const char *file_line) :{ :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex = NULL; :#endif : : apr_pool_check_integrity(pool); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) : apr_pool_log_event(pool, "CLEAR", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ : :#if APR_HAS_THREADS : if (pool->parent != NULL) : mutex = pool->parent->mutex; : : /* Lock the parent mutex before clearing so that if we have our : * own mutex it won't be accessed by apr_pool_walk_tree after : * it has been destroyed. : */ : if (mutex != NULL && mutex != pool->mutex) { : apr_thread_mutex_lock(mutex); : } :#endif : : pool_clear_debug(pool, file_line); : :#if APR_HAS_THREADS : /* If we had our own mutex, it will have been destroyed by : * the registered cleanups. Recreate the mutex. Unlock : * the mutex we obtained above. : */ : if (mutex != pool->mutex) { : (void)apr_thread_mutex_create(&pool->mutex, : APR_THREAD_MUTEX_NESTED, pool); : : if (mutex != NULL) : (void)apr_thread_mutex_unlock(mutex); : } :#endif /* APR_HAS_THREADS */ :} : :static void pool_destroy_debug(apr_pool_t *pool, const char *file_line) :{ : apr_pool_check_integrity(pool); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) : apr_pool_log_event(pool, "DESTROY", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ : : pool_clear_debug(pool, file_line); : : /* Remove the pool from the parents child list */ : if (pool->parent) { :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : if ((mutex = pool->parent->mutex) != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : if ((*pool->ref = pool->sibling) != NULL) : pool->sibling->ref = pool->ref; : :#if APR_HAS_THREADS : if (mutex) : apr_thread_mutex_unlock(mutex); :#endif /* APR_HAS_THREADS */ : } : : if (pool->allocator != NULL : && apr_allocator_owner_get(pool->allocator) == pool) { : apr_allocator_destroy(pool->allocator); : } : : /* Free the pool itself */ : free(pool); :} : :APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool, : const char *file_line) :{ : if (pool->joined) { : /* Joined pools must not be explicitly destroyed; the caller : * has broken the guarantee. */ :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : apr_pool_log_event(pool, "LIFE", : __FILE__ ":apr_pool_destroy abort on joined", 0); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : : abort(); : } : pool_destroy_debug(pool, file_line); :} : :APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator, : const char *file_line) :{ : apr_pool_t *pool; : : *newpool = NULL; : : if (!parent) { : parent = global_pool; : } : else { : apr_pool_check_integrity(parent); : : if (!allocator) : allocator = parent->allocator; : } : : if (!abort_fn && parent) : abort_fn = parent->abort_fn; : : if ((pool = malloc(SIZEOF_POOL_T)) == NULL) { : if (abort_fn) : abort_fn(APR_ENOMEM); : : return APR_ENOMEM; : } : : memset(pool, 0, SIZEOF_POOL_T); : : pool->allocator = allocator; : pool->abort_fn = abort_fn; : pool->tag = file_line; : pool->file_line = file_line; : : if ((pool->parent = parent) != NULL) { :#if APR_HAS_THREADS : if (parent->mutex) : apr_thread_mutex_lock(parent->mutex); :#endif /* APR_HAS_THREADS */ : if ((pool->sibling = parent->child) != NULL) : pool->sibling->ref = &pool->sibling; : : parent->child = pool; : pool->ref = &parent->child; : :#if APR_HAS_THREADS : if (parent->mutex) : apr_thread_mutex_unlock(parent->mutex); :#endif /* APR_HAS_THREADS */ : } : else { : pool->sibling = NULL; : pool->ref = NULL; : } : :#if APR_HAS_THREADS : pool->owner = apr_os_thread_current(); :#endif /* APR_HAS_THREADS */ :#ifdef NETWARE : pool->owner_proc = (apr_os_proc_t)getnlmhandle(); :#endif /* defined(NETWARE) */ : : : if (parent == NULL || parent->allocator != allocator) { :#if APR_HAS_THREADS : apr_status_t rv; : : /* No matter what the creation flags say, always create : * a lock. Without it integrity_check and apr_pool_num_bytes : * blow up (because they traverse pools child lists that : * possibly belong to another thread, in combination with : * the pool having no lock). However, this might actually : * hide problems like creating a child pool of a pool : * belonging to another thread. : */ : if ((rv = apr_thread_mutex_create(&pool->mutex, : APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) { : free(pool); : return rv; : } :#endif /* APR_HAS_THREADS */ : } : else { :#if APR_HAS_THREADS : if (parent) : pool->mutex = parent->mutex; :#endif /* APR_HAS_THREADS */ : } : : *newpool = pool; : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) : apr_pool_log_event(pool, "CREATE", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ : : return APR_SUCCESS; :} : : :/* : * "Print" functions (debug) : */ : :struct psprintf_data { : apr_vformatter_buff_t vbuff; : char *mem; : apr_size_t size; :}; : :static int psprintf_flush(apr_vformatter_buff_t *vbuff) :{ : struct psprintf_data *ps = (struct psprintf_data *)vbuff; : apr_size_t size; : : size = ps->vbuff.curpos - ps->mem; : : ps->size <<= 1; : if ((ps->mem = realloc(ps->mem, ps->size)) == NULL) : return -1; : : ps->vbuff.curpos = ps->mem + size; : ps->vbuff.endpos = ps->mem + ps->size - 1; : : return 0; :} : :APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) :{ : struct psprintf_data ps; : debug_node_t *node; : : apr_pool_check_integrity(pool); : : ps.size = 64; : ps.mem = malloc(ps.size); : ps.vbuff.curpos = ps.mem; : : /* Save a byte for the NUL terminator */ : ps.vbuff.endpos = ps.mem + ps.size - 1; : : if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : *ps.vbuff.curpos++ = '\0'; : : /* : * Link the node in : */ : node = pool->nodes; : if (node == NULL || node->index == 64) { : if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : node->next = pool->nodes; : pool->nodes = node; : node->index = 0; : } : : node->beginp[node->index] = ps.mem; : node->endp[node->index] = ps.mem + ps.size; : node->index++; : : return ps.mem; :} : : :/* : * Debug functions : */ : :APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub) :{ :#if APR_POOL_DEBUG : if (sub->parent != p) { : abort(); : } : sub->joined = p; :#endif :} : :static int pool_find(apr_pool_t *pool, void *data) :{ : void **pmem = (void **)data; : debug_node_t *node; : apr_uint32_t index; : : node = pool->nodes; : : while (node) { : for (index = 0; index < node->index; index++) { : if (node->beginp[index] <= *pmem : && node->endp[index] > *pmem) { : *pmem = pool; : return 1; : } : } : : node = node->next; : } : : return 0; :} : :APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem) :{ : void *pool = (void *)mem; : : if (apr_pool_walk_tree(global_pool, pool_find, &pool)) : return pool; : : return NULL; :} : :static int pool_num_bytes(apr_pool_t *pool, void *data) :{ : apr_size_t *psize = (apr_size_t *)data; : debug_node_t *node; : apr_uint32_t index; : : node = pool->nodes; : : while (node) { : for (index = 0; index < node->index; index++) { : *psize += (char *)node->endp[index] - (char *)node->beginp[index]; : } : : node = node->next; : } : : return 0; :} : :APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *pool, int recurse) :{ : apr_size_t size = 0; : : if (!recurse) { : pool_num_bytes(pool, &size); : : return size; : } : : apr_pool_walk_tree(pool, pool_num_bytes, &size); : : return size; :} : :APR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag) :{ :} : :#endif /* !APR_POOL_DEBUG */ : :#ifdef NETWARE :void netware_pool_proc_cleanup () :{ : apr_pool_t *pool = global_pool->child; : apr_os_proc_t owner_proc = (apr_os_proc_t)getnlmhandle(); : : while (pool) { : if (pool->owner_proc == owner_proc) { : apr_pool_destroy (pool); : pool = global_pool->child; : } : else { : pool = pool->sibling; : } : } : return; :} :#endif /* defined(NETWARE) */ : : :/* : * "Print" functions (common) : */ : :APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...) :{ : va_list ap; : char *res; : : va_start(ap, fmt); : res = apr_pvsprintf(p, fmt, ap); : va_end(ap); : return res; :} : :/* : * Pool Properties : */ : :APR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abort_fn, : apr_pool_t *pool) :{ : pool->abort_fn = abort_fn; :} : :APR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool) :{ : return pool->abort_fn; :} : :APR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool) :{ :#ifdef NETWARE : /* On NetWare, don't return the global_pool, return the application pool : as the top most pool */ : if (pool->parent == global_pool) : return NULL; : else :#endif : return pool->parent; :} : :APR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool) :{ : return pool->allocator; :} : :/* return TRUE if a is an ancestor of b : * NULL is considered an ancestor of all pools : */ :APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b) :{ : if (a == NULL) : return 1; : :#if APR_POOL_DEBUG : /* Find the pool with the longest lifetime guaranteed by the : * caller: */ : while (a->joined) { : a = a->joined; : } :#endif : : while (b) { : if (a == b) : return 1; : : b = b->parent; : } : : return 0; :} : :APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag) :{ : pool->tag = tag; :} : : :/* : * User data management : */ : :APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, const char *key, : apr_status_t (*cleanup) (void *), : apr_pool_t *pool) :{ :#if APR_POOL_DEBUG : apr_pool_check_integrity(pool); :#endif /* APR_POOL_DEBUG */ : : if (pool->user_data == NULL) : pool->user_data = apr_hash_make(pool); : : if (apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING) == NULL) { : char *new_key = apr_pstrdup(pool, key); : apr_hash_set(pool->user_data, new_key, APR_HASH_KEY_STRING, data); : } : else { : apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data); : } : : if (cleanup) : apr_pool_cleanup_register(pool, data, cleanup, cleanup); : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_pool_userdata_setn(const void *data, : const char *key, : apr_status_t (*cleanup)(void *), : apr_pool_t *pool) :{ :#if APR_POOL_DEBUG : apr_pool_check_integrity(pool); :#endif /* APR_POOL_DEBUG */ : : if (pool->user_data == NULL) : pool->user_data = apr_hash_make(pool); : : apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data); : : if (cleanup) : apr_pool_cleanup_register(pool, data, cleanup, cleanup); : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key, : apr_pool_t *pool) :{ :#if APR_POOL_DEBUG : apr_pool_check_integrity(pool); :#endif /* APR_POOL_DEBUG */ : : if (pool->user_data == NULL) { : *data = NULL; : } : else { : *data = apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING); : } : : return APR_SUCCESS; :} : : :/* : * Cleanup : */ : :struct cleanup_t { : struct cleanup_t *next; : const void *data; : apr_status_t (*plain_cleanup_fn)(void *data); : apr_status_t (*child_cleanup_fn)(void *data); :}; : :APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void *data, : apr_status_t (*plain_cleanup_fn)(void *data), : apr_status_t (*child_cleanup_fn)(void *data)) :{ : cleanup_t *c; : :#if APR_POOL_DEBUG : apr_pool_check_integrity(p); :#endif /* APR_POOL_DEBUG */ : : if (p != NULL) { : if (p->free_cleanups) { : /* reuse a cleanup structure */ : c = p->free_cleanups; : p->free_cleanups = c->next; : } else { : c = apr_palloc(p, sizeof(cleanup_t)); : } : c->data = data; : c->plain_cleanup_fn = plain_cleanup_fn; : c->child_cleanup_fn = child_cleanup_fn; : c->next = p->cleanups; : p->cleanups = c; : } :} : :APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data, : apr_status_t (*cleanup_fn)(void *)) :{ : cleanup_t *c, **lastp; : :#if APR_POOL_DEBUG : apr_pool_check_integrity(p); :#endif /* APR_POOL_DEBUG */ : : if (p == NULL) : return; : : c = p->cleanups; : lastp = &p->cleanups; : while (c) { : if (c->data == data && c->plain_cleanup_fn == cleanup_fn) { : *lastp = c->next; : /* move to freelist */ : c->next = p->free_cleanups; : p->free_cleanups = c; : break; : } : : lastp = &c->next; : c = c->next; : } :} : :APR_DECLARE(void) apr_pool_child_cleanup_set(apr_pool_t *p, const void *data, : apr_status_t (*plain_cleanup_fn)(void *), : apr_status_t (*child_cleanup_fn)(void *)) :{ : cleanup_t *c; : :#if APR_POOL_DEBUG : apr_pool_check_integrity(p); :#endif /* APR_POOL_DEBUG */ : : if (p == NULL) : return; : : c = p->cleanups; : while (c) { : if (c->data == data && c->plain_cleanup_fn == plain_cleanup_fn) { : c->child_cleanup_fn = child_cleanup_fn; : break; : } : : c = c->next; : } :} : :APR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data, : apr_status_t (*cleanup_fn)(void *)) :{ /* apr_pool_cleanup_run total: 1 3.2258 */ : apr_pool_cleanup_kill(p, data, cleanup_fn); 1 3.2258 : return (*cleanup_fn)(data); :} : :static void run_cleanups(cleanup_t **cref) :{ /* run_cleanups total: 2 6.4516 */ : cleanup_t *c = *cref; : 2 6.4516 : while (c) { : *cref = c->next; : (*c->plain_cleanup_fn)((void *)c->data); : c = *cref; : } :} : :static void run_child_cleanups(cleanup_t **cref) :{ : cleanup_t *c = *cref; : : while (c) { : *cref = c->next; : (*c->child_cleanup_fn)((void *)c->data); : c = *cref; : } :} : :static void cleanup_pool_for_exec(apr_pool_t *p) :{ : run_child_cleanups(&p->cleanups); : : for (p = p->child; p; p = p->sibling) : cleanup_pool_for_exec(p); :} : :APR_DECLARE(void) apr_pool_cleanup_for_exec(void) :{ :#if !defined(WIN32) && !defined(OS2) : /* : * Don't need to do anything on NT or OS/2, because I : * am actually going to spawn the new process - not : * exec it. All handles that are not inheritable, will : * be automajically closed. The only problem is with : * file handles that are open, but there isn't much : * I can do about that (except if the child decides : * to go out and close them : */ : cleanup_pool_for_exec(global_pool); :#endif /* !defined(WIN32) && !defined(OS2) */ :} : :APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data) :{ : /* do nothing cleanup routine */ : return APR_SUCCESS; :} : :/* Subprocesses don't use the generic cleanup interface because : * we don't want multiple subprocesses to result in multiple : * three-second pauses; the subprocesses have to be "freed" all : * at once. If other resources are introduced with the same property, : * we might want to fold support for that into the generic interface. : * For now, it's a special case. : */ :APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *pool, apr_proc_t *proc, : apr_kill_conditions_e how) :{ : struct process_chain *pc = apr_palloc(pool, sizeof(struct process_chain)); : : pc->proc = proc; : pc->kill_how = how; : pc->next = pool->subprocesses; : pool->subprocesses = pc; :} : :static void free_proc_chain(struct process_chain *procs) :{ : /* Dispose of the subprocesses we've spawned off in the course of : * whatever it was we're cleaning up now. This may involve killing : * some of them off... : */ : struct process_chain *pc; : int need_timeout = 0; : apr_time_t timeout_interval; : : if (!procs) : return; /* No work. Whew! */ : : /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL : * dance with any of the processes we're cleaning up. If we've got : * any kill-on-sight subprocesses, ditch them now as well, so they : * don't waste any more cycles doing whatever it is that they shouldn't : * be doing anymore. : */ : :#ifndef NEED_WAITPID : /* Pick up all defunct processes */ : for (pc = procs; pc; pc = pc->next) { : if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) != APR_CHILD_NOTDONE) : pc->kill_how = APR_KILL_NEVER; : } :#endif /* !defined(NEED_WAITPID) */ : : for (pc = procs; pc; pc = pc->next) { :#ifndef WIN32 : if ((pc->kill_how == APR_KILL_AFTER_TIMEOUT) : || (pc->kill_how == APR_KILL_ONLY_ONCE)) { : /* : * Subprocess may be dead already. Only need the timeout if not. : * Note: apr_proc_kill on Windows is TerminateProcess(), which is : * similar to a SIGKILL, so always give the process a timeout : * under Windows before killing it. : */ : if (apr_proc_kill(pc->proc, SIGTERM) == APR_SUCCESS) : need_timeout = 1; : } : else if (pc->kill_how == APR_KILL_ALWAYS) { :#else /* WIN32 knows only one fast, clean method of killing processes today */ : if (pc->kill_how != APR_KILL_NEVER) { : need_timeout = 1; : pc->kill_how = APR_KILL_ALWAYS; :#endif : apr_proc_kill(pc->proc, SIGKILL); : } : } : : /* Sleep only if we have to. The sleep algorithm grows : * by a factor of two on each iteration. TIMEOUT_INTERVAL : * is equal to TIMEOUT_USECS / 64. : */ : if (need_timeout) { : timeout_interval = TIMEOUT_INTERVAL; : apr_sleep(timeout_interval); : : do { : /* check the status of the subprocesses */ : need_timeout = 0; : for (pc = procs; pc; pc = pc->next) { : if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) { : if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) : == APR_CHILD_NOTDONE) : need_timeout = 1; /* subprocess is still active */ : else : pc->kill_how = APR_KILL_NEVER; /* subprocess has exited */ : } : } : if (need_timeout) { : if (timeout_interval >= TIMEOUT_USECS) { : break; : } : apr_sleep(timeout_interval); : timeout_interval *= 2; : } : } while (need_timeout); : } : : /* OK, the scripts we just timed out for have had a chance to clean up : * --- now, just get rid of them, and also clean up the system accounting : * goop... : */ : for (pc = procs; pc; pc = pc->next) { : if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) : apr_proc_kill(pc->proc, SIGKILL); : } : : /* Now wait for all the signaled processes to die */ : for (pc = procs; pc; pc = pc->next) { : if (pc->kill_how != APR_KILL_NEVER) : (void)apr_proc_wait(pc->proc, NULL, NULL, APR_WAIT); : } :} : : :/* : * Pool creation/destruction stubs, for people who are running : * mixed release/debug enviroments. : */ : :#if !APR_POOL_DEBUG :APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : return apr_palloc(pool, size); :} : :APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : return apr_pcalloc(pool, size); :} : :APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool, : const char *file_line) :{ : apr_pool_clear(pool); :} : :APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool, : const char *file_line) :{ : apr_pool_destroy(pool); :} : :APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator, : const char *file_line) :{ : return apr_pool_create_ex(newpool, parent, abort_fn, allocator); :} : :#else /* APR_POOL_DEBUG */ : :#undef apr_palloc :APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size); : :APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size) :{ : return apr_palloc_debug(pool, size, "undefined"); :} : :#undef apr_pcalloc :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size); : :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size) :{ : return apr_pcalloc_debug(pool, size, "undefined"); :} : :#undef apr_pool_clear :APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool); : :APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool) :{ : apr_pool_clear_debug(pool, "undefined"); :} : :#undef apr_pool_destroy :APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool); : :APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool) :{ : apr_pool_destroy_debug(pool, "undefined"); :} : :#undef apr_pool_create_ex :APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator); : :APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator) :{ : return apr_pool_create_ex_debug(newpool, parent, : abort_fn, allocator, : "undefined"); :} : :#endif /* APR_POOL_DEBUG */ /* * Total samples for file : "locks/unix/thread_mutex.c" * * 4 12.9032 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr_arch_thread_mutex.h" :#define APR_WANT_MEMFUNC :#include "apr_want.h" : :#if APR_HAS_THREADS : :static apr_status_t thread_mutex_cleanup(void *data) :{ : apr_thread_mutex_t *mutex = data; : apr_status_t rv; : : rv = pthread_mutex_destroy(&mutex->mutex); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, : unsigned int flags, : apr_pool_t *pool) 1 3.2258 :{ /* apr_thread_mutex_create total: 1 3.2258 */ : apr_thread_mutex_t *new_mutex; : apr_status_t rv; : :#ifndef HAVE_PTHREAD_MUTEX_RECURSIVE : if (flags & APR_THREAD_MUTEX_NESTED) { : return APR_ENOTIMPL; : } :#endif : : new_mutex = apr_pcalloc(pool, sizeof(apr_thread_mutex_t)); : new_mutex->pool = pool; : :#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE : if (flags & APR_THREAD_MUTEX_NESTED) { : pthread_mutexattr_t mattr; : : rv = pthread_mutexattr_init(&mattr); : if (rv) return rv; : : rv = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); : if (rv) { : pthread_mutexattr_destroy(&mattr); : return rv; : } : : rv = pthread_mutex_init(&new_mutex->mutex, &mattr); : : pthread_mutexattr_destroy(&mattr); : } else :#endif : rv = pthread_mutex_init(&new_mutex->mutex, NULL); : : if (rv) { :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return rv; : } : : apr_pool_cleanup_register(new_mutex->pool, : new_mutex, thread_mutex_cleanup, : apr_pool_cleanup_null); : : *mutex = new_mutex; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) :{ : apr_status_t rv; : 2 6.4516 : rv = pthread_mutex_lock(&mutex->mutex); /* apr_thread_mutex_lock total: 2 6.4516 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) :{ : apr_status_t rv; : : rv = pthread_mutex_trylock(&mutex->mutex); : if (rv) { :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return (rv == EBUSY) ? APR_EBUSY : rv; : } : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) :{ : apr_status_t status; : 1 3.2258 : status = pthread_mutex_unlock(&mutex->mutex); /* apr_thread_mutex_unlock total: 1 3.2258 */ :#ifdef PTHREAD_SETS_ERRNO : if (status) { : status = errno; : } :#endif : : return status; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) :{ : return apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); :} : :APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) : :#endif /* APR_HAS_THREADS */ /* * Total samples for file : "network_io/unix/sendrecv.c" * * 3 9.6774 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr_arch_networkio.h" :#include "apr_support.h" : :#if APR_HAS_SENDFILE :/* This file is needed to allow us access to the apr_file_t internals. */ :#include "apr_arch_file_io.h" :#endif /* APR_HAS_SENDFILE */ : :/* osreldate.h is only needed on FreeBSD for sendfile detection */ :#if defined(__FreeBSD__) :#include :#endif : :apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf, : apr_size_t *len) :{ : apr_ssize_t rv; : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = write(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : : while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv; :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = write(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : *len = 0; : return errno; : } : if ((sock->timeout > 0) && (rv < *len)) { : sock->options |= APR_INCOMPLETE_WRITE; : } : (*len) = rv; : return APR_SUCCESS; :} : :apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) :{ : apr_ssize_t rv; : apr_status_t arv; : : if (sock->options & APR_INCOMPLETE_READ) { : sock->options &= ~APR_INCOMPLETE_READ; : goto do_select; : } : : do { : rv = read(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 1); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = read(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : (*len) = 0; : return errno; : } : if ((sock->timeout > 0) && (rv < *len)) { : sock->options |= APR_INCOMPLETE_READ; : } : (*len) = rv; : if (rv == 0) { : return APR_EOF; : } : return APR_SUCCESS; :} : :apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where, : apr_int32_t flags, const char *buf, : apr_size_t *len) :{ : apr_ssize_t rv; : : do { : rv = sendto(sock->socketdes, buf, (*len), flags, : (const struct sockaddr*)&where->sa, : where->salen); : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } else { : do { : rv = sendto(sock->socketdes, buf, (*len), flags, : (const struct sockaddr*)&where->sa, : where->salen); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : *len = 0; : return errno; : } : *len = rv; : return APR_SUCCESS; :} : :apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, : apr_int32_t flags, char *buf, : apr_size_t *len) :{ /* apr_socket_recvfrom total: 3 9.6774 */ : apr_ssize_t rv; : : do { : rv = recvfrom(sock->socketdes, buf, (*len), flags, : (struct sockaddr*)&from->sa, &from->salen); 1 3.2258 : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } else { : do { : rv = recvfrom(sock->socketdes, buf, (*len), flags, : (struct sockaddr*)&from->sa, &from->salen); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : (*len) = 0; : return errno; : } : : (*len) = rv; : if (rv == 0 && sock->type == SOCK_STREAM) { : return APR_EOF; : } : : return APR_SUCCESS; 2 6.4516 :} : :#ifdef HAVE_WRITEV :apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec, : apr_int32_t nvec, apr_size_t *len) :{ : apr_ssize_t rv; : apr_size_t requested_len = 0; : apr_int32_t i; : : for (i = 0; i < nvec; i++) { : requested_len += vec[i].iov_len; : } : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = writev(sock->socketdes, vec, nvec); : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv; :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = writev(sock->socketdes, vec, nvec); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : *len = 0; : return errno; : } : if ((sock->timeout > 0) && (rv < requested_len)) { : sock->options |= APR_INCOMPLETE_WRITE; : } : (*len) = rv; : return APR_SUCCESS; :} :#endif : :#if APR_HAS_SENDFILE : :/* TODO: Verify that all platforms handle the fd the same way, : * i.e. that they don't move the file pointer. : */ :/* TODO: what should flags be? int_32? */ : :/* Define a structure to pass in when we have a NULL header value */ :static apr_hdtr_t no_hdtr; : :#if defined(__linux__) && defined(HAVE_WRITEV) : :apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, : apr_hdtr_t *hdtr, apr_off_t *offset, : apr_size_t *len, apr_int32_t flags) :{ : int rv, nbytes = 0, total_hdrbytes, i; : apr_status_t arv; : :#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) : apr_off_t off = *offset; :#define sendfile sendfile64 : :#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 : /* 64-bit apr_off_t but no sendfile64(): fail if trying to send : * past the 2Gb limit. */ : off_t off; : : if ((apr_int64_t)*offset + *len > INT_MAX) { : return EINVAL; : } : : off = *offset; : :#else : off_t off = *offset; :#endif : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : if (hdtr->numheaders > 0) { : apr_size_t hdrbytes; : : /* cork before writing headers */ : rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 1); : if (rv != APR_SUCCESS) { : return rv; : } : : /* Now write the headers */ : arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, : &hdrbytes); : if (arv != APR_SUCCESS) { : *len = 0; : return errno; : } : nbytes += hdrbytes; : : /* If this was a partial write and we aren't doing timeouts, : * return now with the partial byte count; this is a non-blocking : * socket. : */ : total_hdrbytes = 0; : for (i = 0; i < hdtr->numheaders; i++) { : total_hdrbytes += hdtr->headers[i].iov_len; : } : if (hdrbytes < total_hdrbytes) { : *len = hdrbytes; : return apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : } : } : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = sendfile(sock->socketdes, /* socket */ : file->filedes, /* open file descriptor of the file to be sent */ : &off, /* where in the file to start */ : *len); /* number of bytes to send */ : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = sendfile(sock->socketdes, /* socket */ : file->filedes, /* open file descriptor of the file to be sent */ : &off, /* where in the file to start */ : *len); /* number of bytes to send */ : } while (rv == -1 && errno == EINTR); : } : } : : if (rv == -1) { : *len = nbytes; : rv = errno; : apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : return rv; : } : : nbytes += rv; : : if (rv < *len) { : *len = nbytes; : arv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : if (rv > 0) { : : /* If this was a partial write, return now with the : * partial byte count; this is a non-blocking socket. : */ : : if (sock->timeout > 0) { : sock->options |= APR_INCOMPLETE_WRITE; : } : return arv; : } : else { : /* If the file got smaller mid-request, eventually the offset : * becomes equal to the new file size and the kernel returns 0. : * Make this an error so the caller knows to log something and : * exit. : */ : return APR_EOF; : } : } : : /* Now write the footers */ : if (hdtr->numtrailers > 0) { : apr_size_t trbytes; : arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, : &trbytes); : nbytes += trbytes; : if (arv != APR_SUCCESS) { : *len = nbytes; : rv = errno; : apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : return rv; : } : } : : apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : : (*len) = nbytes; : return rv < 0 ? errno : APR_SUCCESS; :} : :#elif defined(__FreeBSD__) || defined(__DragonFly__) : :/* Release 3.1 or greater */ :apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, : apr_hdtr_t * hdtr, apr_off_t * offset, : apr_size_t * len, apr_int32_t flags) :{ : off_t nbytes = 0; : int rv, i; : struct sf_hdtr headerstruct; : apr_size_t bytes_to_send = *len; : : /* Ignore flags for now. */ : flags = 0; : : if (!hdtr) { : hdtr = &no_hdtr; : } : :#if defined(__FreeBSD_version) && __FreeBSD_version < 460001 : else if (hdtr->numheaders) { : : /* On early versions of FreeBSD sendfile, the number of bytes to send : * must include the length of the headers. Don't look at the man page : * for this :( Instead, look at the the logic in : * src/sys/kern/uipc_syscalls::sendfile(). : * : * This was fixed in the middle of 4.6-STABLE : */ : for (i = 0; i < hdtr->numheaders; i++) { : bytes_to_send += hdtr->headers[i].iov_len; : } : } :#endif : : headerstruct.headers = hdtr->headers; : headerstruct.hdr_cnt = hdtr->numheaders; : headerstruct.trailers = hdtr->trailers; : headerstruct.trl_cnt = hdtr->numtrailers; : : /* FreeBSD can send the headers/footers as part of the system call */ : do { : if (sock->options & APR_INCOMPLETE_WRITE) { : apr_status_t arv; : sock->options &= ~APR_INCOMPLETE_WRITE; : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : } : if (bytes_to_send) { : /* We won't dare call sendfile() if we don't have : * header or file bytes to send because bytes_to_send == 0 : * means send the whole file. : */ : rv = sendfile(file->filedes, /* file to be sent */ : sock->socketdes, /* socket */ : *offset, /* where in the file to start */ : bytes_to_send, /* number of bytes to send */ : &headerstruct, /* Headers/footers */ : &nbytes, /* number of bytes written */ : flags); /* undefined, set to 0 */ : : if (rv == -1) { : if (errno == EAGAIN) { : if (sock->timeout > 0) { : sock->options |= APR_INCOMPLETE_WRITE; : } : /* FreeBSD's sendfile can return -1/EAGAIN even if it : * sent bytes. Sanitize the result so we get normal EAGAIN : * semantics w.r.t. bytes sent. : */ : if (nbytes) { : /* normal exit for a big file & non-blocking io */ : (*len) = nbytes; : return APR_SUCCESS; : } : } : } : else { /* rv == 0 (or the kernel is broken) */ : if (nbytes == 0) { : /* Most likely the file got smaller after the stat. : * Return an error so the caller can do the Right Thing. : */ : (*len) = nbytes; : return APR_EOF; : } : } : } : else { : /* just trailer bytes... use writev() : */ : rv = writev(sock->socketdes, : hdtr->trailers, : hdtr->numtrailers); : if (rv > 0) { : nbytes = rv; : rv = 0; : } : else { : nbytes = 0; : } : } : if ((rv == -1) && (errno == EAGAIN) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : } : } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); : : (*len) = nbytes; : if (rv == -1) { : return errno; : } : return APR_SUCCESS; :} : :#elif defined(__hpux) || defined(__hpux__) : :/* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */ : :/* HP-UX Version 10.30 or greater : * (no worries, because we only get here if autoconfiguration found sendfile) : */ : :/* ssize_t sendfile(int s, int fd, off_t offset, size_t nbytes, : * const struct iovec *hdtrl, int flags); : * : * nbytes is the number of bytes to send just from the file; as with FreeBSD, : * if nbytes == 0, the rest of the file (from offset) is sent : */ : :apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, : apr_hdtr_t *hdtr, apr_off_t *offset, : apr_size_t *len, apr_int32_t flags) :{ : int i; : apr_ssize_t rc; : apr_size_t nbytes = *len, headerlen, trailerlen; : struct iovec hdtrarray[2]; : char *headerbuf, *trailerbuf; : :#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) : /* later HP-UXes have a sendfile64() */ :#define sendfile sendfile64 : apr_off_t off = *offset; : :#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 : /* HP-UX 11.00 doesn't have a sendfile64(): fail if trying to send : * past the 2Gb limit */ : off_t off; : : if ((apr_int64_t)*offset + *len > INT_MAX) { : return EINVAL; : } : off = *offset; :#else : apr_off_t off = *offset; :#endif : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : /* HP-UX can only send one header iovec and one footer iovec; try to : * only allocate storage to combine input iovecs when we really have to : */ : : switch(hdtr->numheaders) { : case 0: : hdtrarray[0].iov_base = NULL; : hdtrarray[0].iov_len = 0; : break; : case 1: : hdtrarray[0] = hdtr->headers[0]; : break; : default: : headerlen = 0; : for (i = 0; i < hdtr->numheaders; i++) { : headerlen += hdtr->headers[i].iov_len; : } : : /* XXX: BUHHH? wow, what a memory leak! */ : headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->pool, headerlen); : hdtrarray[0].iov_len = headerlen; : : for (i = 0; i < hdtr->numheaders; i++) { : memcpy(headerbuf, hdtr->headers[i].iov_base, : hdtr->headers[i].iov_len); : headerbuf += hdtr->headers[i].iov_len; : } : } : : switch(hdtr->numtrailers) { : case 0: : hdtrarray[1].iov_base = NULL; : hdtrarray[1].iov_len = 0; : break; : case 1: : hdtrarray[1] = hdtr->trailers[0]; : break; : default: : trailerlen = 0; : for (i = 0; i < hdtr->numtrailers; i++) { : trailerlen += hdtr->trailers[i].iov_len; : } : : /* XXX: BUHHH? wow, what a memory leak! */ : trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->pool, trailerlen); : hdtrarray[1].iov_len = trailerlen; : : for (i = 0; i < hdtr->numtrailers; i++) { : memcpy(trailerbuf, hdtr->trailers[i].iov_base, : hdtr->trailers[i].iov_len); : trailerbuf += hdtr->trailers[i].iov_len; : } : } : : do { : if (nbytes) { /* any bytes to send from the file? */ : rc = sendfile(sock->socketdes, /* socket */ : file->filedes, /* file descriptor to send */ : off, /* where in the file to start */ : nbytes, /* number of bytes to send from file */ : hdtrarray, /* Headers/footers */ : flags); /* undefined, set to 0 */ : } : else { /* we can't call sendfile() with no bytes to send from the file */ : rc = writev(sock->socketdes, hdtrarray, 2); : } : } while (rc == -1 && errno == EINTR); : : while ((rc == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : if (nbytes) { : rc = sendfile(sock->socketdes, /* socket */ : file->filedes, /* file descriptor to send */ : off, /* where in the file to start */ : nbytes, /* number of bytes to send from file */ : hdtrarray, /* Headers/footers */ : flags); /* undefined, set to 0 */ : } : else { /* we can't call sendfile() with no bytes to send from the file */ : rc = writev(sock->socketdes, hdtrarray, 2); : } : } while (rc == -1 && errno == EINTR); : } : } : : if (rc == -1) { : *len = 0; : return errno; : } : : /* Set len to the number of bytes written */ : *len = rc; : return APR_SUCCESS; :} :#elif defined(_AIX) || defined(__MVS__) :/* AIX and OS/390 have the same send_file() interface. : * : * subtle differences: : * AIX doesn't update the file ptr but OS/390 does : * : * availability (correctly determined by autoconf): : * : * AIX - version 4.3.2 with APAR IX85388, or version 4.3.3 and above : * OS/390 - V2R7 and above : */ :apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, : apr_hdtr_t * hdtr, apr_off_t * offset, : apr_size_t * len, apr_int32_t flags) :{ : int i, ptr, rv = 0; : void * hbuf=NULL, * tbuf=NULL; : apr_status_t arv; : struct sf_parms parms; : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : /* word to the wise: by default, AIX stores files sent by send_file() : * in the network buffer cache... there are supposedly scenarios : * where the most recent copy of the file won't be sent, but I can't : * recreate the potential problem, perhaps because of the way we : * use send_file()... if you suspect such a problem, try turning : * on the SF_SYNC_CACHE flag : */ : : /* AIX can also send the headers/footers as part of the system call */ : parms.header_length = 0; : if (hdtr && hdtr->numheaders) { : if (hdtr->numheaders == 1) { : parms.header_data = hdtr->headers[0].iov_base; : parms.header_length = hdtr->headers[0].iov_len; : } : else { : for (i = 0; i < hdtr->numheaders; i++) { : parms.header_length += hdtr->headers[i].iov_len; : } :#if 0 : /* Keepalives make apr_palloc a bad idea */ : hbuf = malloc(parms.header_length); :#else : /* but headers are small, so maybe we can hold on to the : * memory for the life of the socket... : */ : hbuf = apr_palloc(sock->pool, parms.header_length); :#endif : ptr = 0; : for (i = 0; i < hdtr->numheaders; i++) { : memcpy((char *)hbuf + ptr, hdtr->headers[i].iov_base, : hdtr->headers[i].iov_len); : ptr += hdtr->headers[i].iov_len; : } : parms.header_data = hbuf; : } : } : else parms.header_data = NULL; : parms.trailer_length = 0; : if (hdtr && hdtr->numtrailers) { : if (hdtr->numtrailers == 1) { : parms.trailer_data = hdtr->trailers[0].iov_base; : parms.trailer_length = hdtr->trailers[0].iov_len; : } : else { : for (i = 0; i < hdtr->numtrailers; i++) { : parms.trailer_length += hdtr->trailers[i].iov_len; : } :#if 0 : /* Keepalives make apr_palloc a bad idea */ : tbuf = malloc(parms.trailer_length); :#else : tbuf = apr_palloc(sock->pool, parms.trailer_length); :#endif : ptr = 0; : for (i = 0; i < hdtr->numtrailers; i++) { : memcpy((char *)tbuf + ptr, hdtr->trailers[i].iov_base, : hdtr->trailers[i].iov_len); : ptr += hdtr->trailers[i].iov_len; : } : parms.trailer_data = tbuf; : } : } : else { : parms.trailer_data = NULL; : } : : /* Whew! Headers and trailers set up. Now for the file data */ : : parms.file_descriptor = file->filedes; : parms.file_offset = *offset; : parms.file_bytes = *len; : : /* O.K. All set up now. Let's go to town */ : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = send_file(&(sock->socketdes), /* socket */ : &(parms), /* all data */ : flags); /* flags */ : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = send_file(&(sock->socketdes), /* socket */ : &(parms), /* all data */ : flags); /* flags */ : } while (rv == -1 && errno == EINTR); : } : } : : (*len) = parms.bytes_sent; : :#if 0 : /* Clean up after ourselves */ : if(hbuf) free(hbuf); : if(tbuf) free(tbuf); :#endif : : if (rv == -1) { : return errno; : } : : if ((sock->timeout > 0) : && (parms.bytes_sent : < (parms.file_bytes + parms.header_length + parms.trailer_length))) { : sock->options |= APR_INCOMPLETE_WRITE; : } : : return APR_SUCCESS; :} :#elif defined(__osf__) && defined (__alpha) :/* Tru64's sendfile implementation doesn't work, and we need to make sure that : * we don't use it until it is fixed. If it is used as it is now, it will : * hang the machine and the only way to fix it is a reboot. : */ :#elif defined(HAVE_SENDFILEV) :/* Solaris 8's sendfilev() interface : * : * SFV_FD_SELF refers to our memory space. : * : * Required Sparc patches (or newer): : * 111297-01, 108528-09, 109472-06, 109234-03, 108995-02, 111295-01, 109025-03, : * 108991-13 : * Required x86 patches (or newer): : * 111298-01, 108529-09, 109473-06, 109235-04, 108996-02, 111296-01, 109026-04, : * 108992-13 : */ : :#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILEV64) :#define sendfilevec_t sendfilevec64_t :#define sendfilev sendfilev64 :#endif : :apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, : apr_hdtr_t *hdtr, apr_off_t *offset, : apr_size_t *len, apr_int32_t flags) :{ : apr_status_t rv, arv; : apr_size_t nbytes; : sendfilevec_t *sfv; : int vecs, curvec, i, repeat; : apr_size_t requested_len = 0; : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : /* Calculate how much space we need. */ : vecs = hdtr->numheaders + hdtr->numtrailers + 1; : sfv = apr_palloc(sock->pool, sizeof(sendfilevec_t) * vecs); : : curvec = 0; : : /* Add the headers */ : for (i = 0; i < hdtr->numheaders; i++, curvec++) { : sfv[curvec].sfv_fd = SFV_FD_SELF; : sfv[curvec].sfv_flag = 0; : sfv[curvec].sfv_off = (apr_off_t)hdtr->headers[i].iov_base; : sfv[curvec].sfv_len = hdtr->headers[i].iov_len; : requested_len += sfv[curvec].sfv_len; : } : : /* If the len is 0, we skip the file. */ : if (*len) : { : sfv[curvec].sfv_fd = file->filedes; : sfv[curvec].sfv_flag = 0; : sfv[curvec].sfv_off = *offset; : sfv[curvec].sfv_len = *len; : requested_len += sfv[curvec].sfv_len; : : curvec++; : } : else { : vecs--; : } : : /* Add the footers */ : for (i = 0; i < hdtr->numtrailers; i++, curvec++) { : sfv[curvec].sfv_fd = SFV_FD_SELF; : sfv[curvec].sfv_flag = 0; : sfv[curvec].sfv_off = (apr_off_t)hdtr->trailers[i].iov_base; : sfv[curvec].sfv_len = hdtr->trailers[i].iov_len; : requested_len += sfv[curvec].sfv_len; : } : : /* If the last write couldn't send all the requested data, : * wait for the socket to become writable before proceeding : */ : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : } : : /* Actually do the sendfilev : * : * Solaris may return -1/EAGAIN even if it sent bytes on a non-block sock. : * : * If no bytes were originally sent (nbytes == 0) and we are on a TIMEOUT : * socket (which as far as the OS is concerned is a non-blocking socket), : * we want to retry after waiting for the other side to read the data (as : * determined by poll). Once it is clear to send, we want to retry : * sending the sendfilevec_t once more. : */ : arv = 0; : do { : /* Clear out the repeat */ : repeat = 0; : : /* socket, vecs, number of vecs, bytes written */ : rv = sendfilev(sock->socketdes, sfv, vecs, &nbytes); : : if (rv == -1 && errno == EAGAIN) { : if (nbytes) { : rv = 0; : } : else if (!arv && (sock->timeout > 0)) { : apr_status_t t = apr_wait_for_io_or_timeout(NULL, sock, 0); : : if (t != APR_SUCCESS) { : *len = 0; : return t; : } : : arv = 1; : repeat = 1; : } : } : } while ((rv == -1 && errno == EINTR) || repeat); : : if (rv == -1) { : *len = 0; : return errno; : } : : /* Update how much we sent */ : *len = nbytes; : if ((sock->timeout > 0) && (*len < requested_len)) { : sock->options |= APR_INCOMPLETE_WRITE; : } : return APR_SUCCESS; :} :#else :#error APR has detected sendfile on your system, but nobody has written a :#error version of it for APR yet. To get past this, either write :#error apr_socket_sendfile or change APR_HAS_SENDFILE in apr.h to 0. :#endif /* __linux__, __FreeBSD__, __DragonFly__, __HPUX__, _AIX, __MVS__, : Tru64/OSF1 */ : :#endif /* APR_HAS_SENDFILE */ /* * Total samples for file : "time/unix/time.c" * * 2 6.4516 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr_portable.h" :#include "apr_time.h" :#include "apr_lib.h" :#include "apr_private.h" :#include "apr_strings.h" : :/* private APR headers */ :#include "apr_arch_internal_time.h" : :/* System Headers required for time library */ :#if APR_HAVE_SYS_TIME_H :#include :#endif :#if APR_HAVE_UNISTD_H :#include :#endif :#ifdef HAVE_TIME_H :#include :#endif :/* End System Headers */ : :#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_STRUCT_TM___TM_GMTOFF) :static apr_int32_t server_gmt_offset; :#define NO_GMTOFF_IN_STRUCT_TM :#endif : :static apr_int32_t get_offset(struct tm *tm) :{ :#if defined(HAVE_STRUCT_TM_TM_GMTOFF) : return tm->tm_gmtoff; :#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) : return tm->__tm_gmtoff; :#else :#ifdef NETWARE : /* Need to adjust the global variable each time otherwise : the web server would have to be restarted when daylight : savings changes. : */ : if (daylightOnOff) { : return server_gmt_offset + daylightOffset; : } :#else : if (tm->tm_isdst) : return server_gmt_offset + 3600; :#endif : return server_gmt_offset; :#endif :} : :APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result, : time_t input) :{ : *result = (apr_time_t)input * APR_USEC_PER_SEC; : return APR_SUCCESS; :} : :/* NB NB NB NB This returns GMT!!!!!!!!!! */ :APR_DECLARE(apr_time_t) apr_time_now(void) :{ /* apr_time_now total: 1 3.2258 */ : struct timeval tv; 1 3.2258 : gettimeofday(&tv, NULL); : return tv.tv_sec * APR_USEC_PER_SEC + tv.tv_usec; :} : :static void explode_time(apr_time_exp_t *xt, apr_time_t t, : apr_int32_t offset, int use_localtime) :{ : struct tm tm; : time_t tt = (t / APR_USEC_PER_SEC) + offset; : xt->tm_usec = t % APR_USEC_PER_SEC; : :#if APR_HAS_THREADS && defined (_POSIX_THREAD_SAFE_FUNCTIONS) : if (use_localtime) : localtime_r(&tt, &tm); : else : gmtime_r(&tt, &tm); :#else : if (use_localtime) : tm = *localtime(&tt); : else : tm = *gmtime(&tt); :#endif : : xt->tm_sec = tm.tm_sec; : xt->tm_min = tm.tm_min; : xt->tm_hour = tm.tm_hour; : xt->tm_mday = tm.tm_mday; : xt->tm_mon = tm.tm_mon; : xt->tm_year = tm.tm_year; : xt->tm_wday = tm.tm_wday; : xt->tm_yday = tm.tm_yday; : xt->tm_isdst = tm.tm_isdst; : xt->tm_gmtoff = get_offset(&tm); :} : :APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result, : apr_time_t input, apr_int32_t offs) :{ : explode_time(result, input, offs, 0); : result->tm_gmtoff = offs; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, : apr_time_t input) :{ : return apr_time_exp_tz(result, input, 0); :} : :APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, : apr_time_t input) :{ :#if defined(__EMX__) : /* EMX gcc (OS/2) has a timezone global we can use */ : return apr_time_exp_tz(result, input, -timezone); :#else : explode_time(result, input, 0, 1); : return APR_SUCCESS; :#endif /* __EMX__ */ :} : :APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, apr_time_exp_t *xt) :{ : apr_time_t year = xt->tm_year; : apr_time_t days; : static const int dayoffset[12] = : {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; : : /* shift new year to 1st March in order to make leap year calc easy */ : : if (xt->tm_mon < 2) : year--; : : /* Find number of days since 1st March 1900 (in the Gregorian calendar). */ : : days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4; : days += dayoffset[xt->tm_mon] + xt->tm_mday - 1; : days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ : days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec; : : if (days < 0) { : return APR_EBADDATE; : } : *t = days * APR_USEC_PER_SEC + xt->tm_usec; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t, : apr_time_exp_t *xt) :{ : apr_status_t status = apr_time_exp_get(t, xt); : if (status == APR_SUCCESS) : *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC; : return status; :} : :APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime, : apr_time_t *aprtime) :{ : (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC; : (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime, : apr_time_exp_t *aprtime) :{ : (*ostime)->tm_sec = aprtime->tm_sec; : (*ostime)->tm_min = aprtime->tm_min; : (*ostime)->tm_hour = aprtime->tm_hour; : (*ostime)->tm_mday = aprtime->tm_mday; : (*ostime)->tm_mon = aprtime->tm_mon; : (*ostime)->tm_year = aprtime->tm_year; : (*ostime)->tm_wday = aprtime->tm_wday; : (*ostime)->tm_yday = aprtime->tm_yday; : (*ostime)->tm_isdst = aprtime->tm_isdst; : :#if defined(HAVE_STRUCT_TM_TM_GMTOFF) : (*ostime)->tm_gmtoff = aprtime->tm_gmtoff; :#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) : (*ostime)->__tm_gmtoff = aprtime->tm_gmtoff; :#endif : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime, : apr_os_imp_time_t **ostime, : apr_pool_t *cont) :{ : *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime, : apr_os_exp_time_t **ostime, : apr_pool_t *cont) :{ : aprtime->tm_sec = (*ostime)->tm_sec; : aprtime->tm_min = (*ostime)->tm_min; : aprtime->tm_hour = (*ostime)->tm_hour; : aprtime->tm_mday = (*ostime)->tm_mday; : aprtime->tm_mon = (*ostime)->tm_mon; : aprtime->tm_year = (*ostime)->tm_year; : aprtime->tm_wday = (*ostime)->tm_wday; : aprtime->tm_yday = (*ostime)->tm_yday; : aprtime->tm_isdst = (*ostime)->tm_isdst; : :#if defined(HAVE_STRUCT_TM_TM_GMTOFF) : aprtime->tm_gmtoff = (*ostime)->tm_gmtoff; :#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) : aprtime->tm_gmtoff = (*ostime)->__tm_gmtoff; :#endif : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_sleep(apr_interval_time_t t) :{ :#ifdef OS2 : DosSleep(t/1000); :#elif defined(BEOS) : snooze(t); :#elif defined(NETWARE) : delay(t/1000); :#else : struct timeval tv; : tv.tv_usec = t % APR_USEC_PER_SEC; /* apr_sleep total: 1 3.2258 */ : tv.tv_sec = t / APR_USEC_PER_SEC; : select(0, NULL, NULL, NULL, &tv); :#endif 1 3.2258 :} : :#ifdef OS2 :APR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result, : FDATE os2date, : FTIME os2time) :{ : struct tm tmpdate; : : memset(&tmpdate, 0, sizeof(tmpdate)); : tmpdate.tm_hour = os2time.hours; : tmpdate.tm_min = os2time.minutes; : tmpdate.tm_sec = os2time.twosecs * 2; : : tmpdate.tm_mday = os2date.day; : tmpdate.tm_mon = os2date.month - 1; : tmpdate.tm_year = os2date.year + 80; : tmpdate.tm_isdst = -1; : : *result = mktime(&tmpdate) * APR_USEC_PER_SEC; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date, : FTIME *os2time, : apr_time_t aprtime) :{ : time_t ansitime = aprtime / APR_USEC_PER_SEC; : struct tm *lt; : lt = localtime(&ansitime); : os2time->hours = lt->tm_hour; : os2time->minutes = lt->tm_min; : os2time->twosecs = lt->tm_sec / 2; : : os2date->day = lt->tm_mday; : os2date->month = lt->tm_mon + 1; : os2date->year = lt->tm_year - 80; : return APR_SUCCESS; :} :#endif : :#ifdef NETWARE :APR_DECLARE(void) apr_netware_setup_time(void) :{ : tzset(); : server_gmt_offset = -TZONE; :} :#else :APR_DECLARE(void) apr_unix_setup_time(void) :{ :#ifdef NO_GMTOFF_IN_STRUCT_TM : /* Precompute the offset from GMT on systems where it's not : in struct tm. : : Note: This offset is normalized to be independent of daylight : savings time; if the calculation happens to be done in a : time/place where a daylight savings adjustment is in effect, : the returned offset has the same value that it would have : in the same location if daylight savings were not in effect. : The reason for this is that the returned offset can be : applied to a past or future timestamp in explode_time(), : so the DST adjustment obtained from the current time won't : necessarily be applicable. : : mktime() is the inverse of localtime(); so, presumably, : passing in a struct tm made by gmtime() let's us calculate : the true GMT offset. However, there's a catch: if daylight : savings is in effect, gmtime()will set the tm_isdst field : and confuse mktime() into returning a time that's offset : by one hour. In that case, we must adjust the calculated GMT : offset. : : */ : : struct timeval now; : time_t t1, t2; : struct tm t; : : gettimeofday(&now, NULL); : t1 = now.tv_sec; : t2 = 0; : :#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) : gmtime_r(&t1, &t); :#else : t = *gmtime(&t1); :#endif : t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */ : t2 = mktime(&t); : server_gmt_offset = (apr_int32_t) difftime(t1, t2); :#endif /* NO_GMTOFF_IN_STRUCT_TM */ :} : :#endif : :/* A noop on all known Unix implementations */ :APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p) :{ : return; :} : : /* * Total samples for file : "tables/apr_hash.c" * * 2 6.4516 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr_private.h" : :#include "apr_general.h" :#include "apr_pools.h" : :#include "apr_hash.h" : :#if APR_HAVE_STDLIB_H :#include :#endif :#if APR_HAVE_STRING_H :#include :#endif : :#if APR_POOL_DEBUG && APR_HAVE_STDIO_H :#include :#endif : :/* : * The internal form of a hash table. : * : * The table is an array indexed by the hash of the key; collisions : * are resolved by hanging a linked list of hash entries off each : * element of the array. Although this is a really simple design it : * isn't too bad given that pools have a low allocation overhead. : */ : :typedef struct apr_hash_entry_t apr_hash_entry_t; : :struct apr_hash_entry_t { : apr_hash_entry_t *next; : unsigned int hash; : const void *key; : apr_ssize_t klen; : const void *val; :}; : :/* : * Data structure for iterating through a hash table. : * : * We keep a pointer to the next hash entry here to allow the current : * hash entry to be freed or otherwise mangled between calls to : * apr_hash_next(). : */ :struct apr_hash_index_t { : apr_hash_t *ht; : apr_hash_entry_t *this, *next; : unsigned int index; :}; : :/* : * The size of the array is always a power of two. We use the maximum : * index rather than the size so that we can use bitwise-AND for : * modular arithmetic. : * The count of hash entries may be greater depending on the chosen : * collision rate. : */ :struct apr_hash_t { : apr_pool_t *pool; : apr_hash_entry_t **array; : apr_hash_index_t iterator; /* For apr_hash_first(NULL, ...) */ : unsigned int count, max; : apr_hashfunc_t hash_func; : apr_hash_entry_t *free; /* List of recycled entries */ :}; : :#define INITIAL_MAX 15 /* tunable == 2^n - 1 */ : : :/* : * Hash creation functions. : */ : :static apr_hash_entry_t **alloc_array(apr_hash_t *ht, unsigned int max) :{ : return apr_pcalloc(ht->pool, sizeof(*ht->array) * (max + 1)); :} : :APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool) :{ : apr_hash_t *ht; : ht = apr_palloc(pool, sizeof(apr_hash_t)); : ht->pool = pool; : ht->free = NULL; : ht->count = 0; : ht->max = INITIAL_MAX; : ht->array = alloc_array(ht, ht->max); : ht->hash_func = apr_hashfunc_default; : return ht; :} : :APR_DECLARE(apr_hash_t *) apr_hash_make_custom(apr_pool_t *pool, : apr_hashfunc_t hash_func) :{ : apr_hash_t *ht = apr_hash_make(pool); : ht->hash_func = hash_func; : return ht; :} : : :/* : * Hash iteration functions. : */ : :APR_DECLARE(apr_hash_index_t *) apr_hash_next(apr_hash_index_t *hi) :{ : hi->this = hi->next; : while (!hi->this) { : if (hi->index > hi->ht->max) : return NULL; : : hi->this = hi->ht->array[hi->index++]; : } : hi->next = hi->this->next; : return hi; :} : :APR_DECLARE(apr_hash_index_t *) apr_hash_first(apr_pool_t *p, apr_hash_t *ht) :{ : apr_hash_index_t *hi; : if (p) : hi = apr_palloc(p, sizeof(*hi)); : else : hi = &ht->iterator; : : hi->ht = ht; : hi->index = 0; : hi->this = NULL; : hi->next = NULL; : return apr_hash_next(hi); :} : :APR_DECLARE(void) apr_hash_this(apr_hash_index_t *hi, : const void **key, : apr_ssize_t *klen, : void **val) :{ : if (key) *key = hi->this->key; : if (klen) *klen = hi->this->klen; : if (val) *val = (void *)hi->this->val; :} : : :/* : * Expanding a hash table : */ : :static void expand_array(apr_hash_t *ht) :{ : apr_hash_index_t *hi; : apr_hash_entry_t **new_array; : unsigned int new_max; : : new_max = ht->max * 2 + 1; : new_array = alloc_array(ht, new_max); : for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) { : unsigned int i = hi->this->hash & new_max; : hi->this->next = new_array[i]; : new_array[i] = hi->this; : } : ht->array = new_array; : ht->max = new_max; :} : :APR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *char_key, : apr_ssize_t *klen) :{ : unsigned int hash = 0; : const unsigned char *key = (const unsigned char *)char_key; : const unsigned char *p; : apr_ssize_t i; : : /* : * This is the popular `times 33' hash algorithm which is used by : * perl and also appears in Berkeley DB. This is one of the best : * known hash functions for strings because it is both computed : * very fast and distributes very well. : * : * The originator may be Dan Bernstein but the code in Berkeley DB : * cites Chris Torek as the source. The best citation I have found : * is "Chris Torek, Hash function for text in C, Usenet message : * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich : * Salz's USENIX 1992 paper about INN which can be found at : * . : * : * The magic of number 33, i.e. why it works better than many other : * constants, prime or not, has never been adequately explained by : * anyone. So I try an explanation: if one experimentally tests all : * multipliers between 1 and 256 (as I did while writing a low-level : * data structure library some time ago) one detects that even : * numbers are not useable at all. The remaining 128 odd numbers : * (except for the number 1) work more or less all equally well. : * They all distribute in an acceptable way and this way fill a hash : * table with an average percent of approx. 86%. : * : * If one compares the chi^2 values of the variants (see : * Bob Jenkins ``Hashing Frequently Asked Questions'' at : * http://burtleburtle.net/bob/hash/hashfaq.html for a description : * of chi^2), the number 33 not even has the best value. But the : * number 33 and a few other equally good numbers like 17, 31, 63, : * 127 and 129 have nevertheless a great advantage to the remaining : * numbers in the large set of possible multipliers: their multiply : * operation can be replaced by a faster operation based on just one : * shift plus either a single addition or subtraction operation. And : * because a hash function has to both distribute good _and_ has to : * be very fast to compute, those few numbers should be preferred. : * : * -- Ralf S. Engelschall : */ : 1 3.2258 : if (*klen == APR_HASH_KEY_STRING) { /* apr_hashfunc_default total: 1 3.2258 */ : for (p = key; *p; p++) { : hash = hash * 33 + *p; : } : *klen = p - key; : } : else { : for (p = key, i = *klen; i; i--, p++) { : hash = hash * 33 + *p; : } : } : : return hash; :} : : :/* : * This is where we keep the details of the hash function and control : * the maximum collision rate. : * : * If val is non-NULL it creates and initializes a new hash entry if : * there isn't already one there; it returns an updatable pointer so : * that hash entries can be removed. : */ : :static apr_hash_entry_t **find_entry(apr_hash_t *ht, : const void *key, : apr_ssize_t klen, : const void *val) 1 3.2258 :{ /* find_entry total: 1 3.2258 */ : apr_hash_entry_t **hep, *he; : unsigned int hash; : : hash = ht->hash_func(key, &klen); : : /* scan linked list */ : for (hep = &ht->array[hash & ht->max], he = *hep; : he; hep = &he->next, he = *hep) { : if (he->hash == hash : && he->klen == klen : && memcmp(he->key, key, klen) == 0) : break; : } : if (he || !val) : return hep; : : /* add a new entry for non-NULL values */ : if ((he = ht->free) != NULL) : ht->free = he->next; : else : he = apr_palloc(ht->pool, sizeof(*he)); : he->next = NULL; : he->hash = hash; : he->key = key; : he->klen = klen; : he->val = val; : *hep = he; : ht->count++; : return hep; :} : :APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool, : const apr_hash_t *orig) :{ : apr_hash_t *ht; : apr_hash_entry_t *new_vals; : unsigned int i, j; : : ht = apr_palloc(pool, sizeof(apr_hash_t) + : sizeof(*ht->array) * (orig->max + 1) + : sizeof(apr_hash_entry_t) * orig->count); : ht->pool = pool; : ht->free = NULL; : ht->count = orig->count; : ht->max = orig->max; : ht->hash_func = orig->hash_func; : ht->array = (apr_hash_entry_t **)((char *)ht + sizeof(apr_hash_t)); : : new_vals = (apr_hash_entry_t *)((char *)(ht) + sizeof(apr_hash_t) + : sizeof(*ht->array) * (orig->max + 1)); : j = 0; : for (i = 0; i <= ht->max; i++) { : apr_hash_entry_t **new_entry = &(ht->array[i]); : apr_hash_entry_t *orig_entry = orig->array[i]; : while (orig_entry) { : *new_entry = &new_vals[j++]; : (*new_entry)->hash = orig_entry->hash; : (*new_entry)->key = orig_entry->key; : (*new_entry)->klen = orig_entry->klen; : (*new_entry)->val = orig_entry->val; : new_entry = &((*new_entry)->next); : orig_entry = orig_entry->next; : } : *new_entry = NULL; : } : return ht; :} : :APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, : const void *key, : apr_ssize_t klen) :{ : apr_hash_entry_t *he; : he = *find_entry(ht, key, klen, NULL); : if (he) : return (void *)he->val; : else : return NULL; :} : :APR_DECLARE(void) apr_hash_set(apr_hash_t *ht, : const void *key, : apr_ssize_t klen, : const void *val) :{ : apr_hash_entry_t **hep; : hep = find_entry(ht, key, klen, val); : if (*hep) { : if (!val) { : /* delete entry */ : apr_hash_entry_t *old = *hep; : *hep = (*hep)->next; : old->next = ht->free; : ht->free = old; : --ht->count; : } : else { : /* replace entry */ : (*hep)->val = val; : /* check that the collision rate isn't too high */ : if (ht->count > ht->max) { : expand_array(ht); : } : } : } : /* else key not present and val==NULL */ :} : :APR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht) :{ : return ht->count; :} : :APR_DECLARE(apr_hash_t*) apr_hash_overlay(apr_pool_t *p, : const apr_hash_t *overlay, : const apr_hash_t *base) :{ : return apr_hash_merge(p, overlay, base, NULL, NULL); :} : :APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p, : const apr_hash_t *overlay, : const apr_hash_t *base, : void * (*merger)(apr_pool_t *p, : const void *key, : apr_ssize_t klen, : const void *h1_val, : const void *h2_val, : const void *data), : const void *data) :{ : apr_hash_t *res; : apr_hash_entry_t *new_vals = NULL; : apr_hash_entry_t *iter; : apr_hash_entry_t *ent; : unsigned int i,j,k; : :#if APR_POOL_DEBUG : /* we don't copy keys and values, so it's necessary that : * overlay->a.pool and base->a.pool have a life span at least : * as long as p : */ : if (!apr_pool_is_ancestor(overlay->pool, p)) { : fprintf(stderr, : "apr_hash_merge: overlay's pool is not an ancestor of p\n"); : abort(); : } : if (!apr_pool_is_ancestor(base->pool, p)) { : fprintf(stderr, : "apr_hash_merge: base's pool is not an ancestor of p\n"); : abort(); : } :#endif : : res = apr_palloc(p, sizeof(apr_hash_t)); : res->pool = p; : res->free = NULL; : res->hash_func = base->hash_func; : res->count = base->count; : res->max = (overlay->max > base->max) ? overlay->max : base->max; : if (base->count + overlay->count > res->max) { : res->max = res->max * 2 + 1; : } : res->array = alloc_array(res, res->max); : if (base->count + overlay->count) { : new_vals = apr_palloc(p, sizeof(apr_hash_entry_t) * : (base->count + overlay->count)); : } : j = 0; : for (k = 0; k <= base->max; k++) { : for (iter = base->array[k]; iter; iter = iter->next) { : i = iter->hash & res->max; : new_vals[j].klen = iter->klen; : new_vals[j].key = iter->key; : new_vals[j].val = iter->val; : new_vals[j].hash = iter->hash; : new_vals[j].next = res->array[i]; : res->array[i] = &new_vals[j]; : j++; : } : } : : for (k = 0; k <= overlay->max; k++) { : for (iter = overlay->array[k]; iter; iter = iter->next) { : i = iter->hash & res->max; : for (ent = res->array[i]; ent; ent = ent->next) { : if ((ent->klen == iter->klen) && : (memcmp(ent->key, iter->key, iter->klen) == 0)) { : if (merger) { : ent->val = (*merger)(p, iter->key, iter->klen, : iter->val, ent->val, data); : } : else { : ent->val = iter->val; : } : break; : } : } : if (!ent) { : new_vals[j].klen = iter->klen; : new_vals[j].key = iter->key; : new_vals[j].val = iter->val; : new_vals[j].hash = iter->hash; : new_vals[j].next = res->array[i]; : res->array[i] = &new_vals[j]; : res->count++; : j++; : } : } : } : return res; :} : :APR_POOL_IMPLEMENT_ACCESSOR(hash) /* * Total samples for file : "threadproc/unix/thread.c" * * 1 3.2258 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr.h" :#include "apr_portable.h" :#include "apr_arch_threadproc.h" : :#if APR_HAS_THREADS : :#if APR_HAVE_PTHREAD_H : :/* Destroy the threadattr object */ :static apr_status_t threadattr_cleanup(void *data) :{ : apr_threadattr_t *attr = data; : apr_status_t rv; : : rv = pthread_attr_destroy(&attr->attr); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, : apr_pool_t *pool) 1 3.2258 :{ /* apr_threadattr_create total: 1 3.2258 */ : apr_status_t stat; : : (*new) = apr_palloc(pool, sizeof(apr_threadattr_t)); : (*new)->pool = pool; : stat = pthread_attr_init(&(*new)->attr); : : if (stat == 0) { : apr_pool_cleanup_register(pool, *new, threadattr_cleanup, : apr_pool_cleanup_null); : return APR_SUCCESS; : } :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; :} : :#define DETACH_ARG(v) ((v) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE) : :APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, : apr_int32_t on) :{ : apr_status_t stat; :#ifdef PTHREAD_ATTR_SETDETACHSTATE_ARG2_ADDR : int arg = DETACH_ARG(v); : : if ((stat = pthread_attr_setdetachstate(&attr->attr, &arg)) == 0) { :#else : if ((stat = pthread_attr_setdetachstate(&attr->attr, : DETACH_ARG(on))) == 0) { :#endif : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } :} : :APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr) :{ : int state; : :#ifdef PTHREAD_ATTR_GETDETACHSTATE_TAKES_ONE_ARG : state = pthread_attr_getdetachstate(&attr->attr); :#else : pthread_attr_getdetachstate(&attr->attr, &state); :#endif : if (state == 1) : return APR_DETACH; : return APR_NOTDETACH; :} : :APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, : apr_size_t stacksize) :{ : int stat; : : stat = pthread_attr_setstacksize(&attr->attr, stacksize); : if (stat == 0) { : return APR_SUCCESS; : } :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; :} : :APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, : apr_size_t size) :{ :#ifdef HAVE_PTHREAD_ATTR_SETGUARDSIZE : apr_status_t rv; : : rv = pthread_attr_setguardsize(&attr->attr, size); : if (rv == 0) { : return APR_SUCCESS; : } :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return rv; :#else : return APR_ENOTIMPL; :#endif :} : :static void *dummy_worker(void *opaque) :{ : apr_thread_t *thread = (apr_thread_t*)opaque; : return thread->func(thread, thread->data); :} : :APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, : apr_threadattr_t *attr, : apr_thread_start_t func, : void *data, : apr_pool_t *pool) :{ : apr_status_t stat; : pthread_attr_t *temp; : : (*new) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); : : if ((*new) == NULL) { : return APR_ENOMEM; : } : : (*new)->td = (pthread_t *)apr_pcalloc(pool, sizeof(pthread_t)); : : if ((*new)->td == NULL) { : return APR_ENOMEM; : } : : (*new)->pool = pool; : (*new)->data = data; : (*new)->func = func; : : if (attr) : temp = &attr->attr; : else : temp = NULL; : : stat = apr_pool_create(&(*new)->pool, pool); : if (stat != APR_SUCCESS) { : return stat; : } : : if ((stat = pthread_create((*new)->td, temp, dummy_worker, (*new))) == 0) { : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } :} : :APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) :{ : return pthread_self(); :} : :APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, : apr_os_thread_t tid2) :{ : return pthread_equal(tid1, tid2); :} : :APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, : apr_status_t retval) :{ : thd->exitval = retval; : apr_pool_destroy(thd->pool); : pthread_exit(NULL); : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, : apr_thread_t *thd) :{ : apr_status_t stat; : apr_status_t *thread_stat; : : if ((stat = pthread_join(*thd->td,(void *)&thread_stat)) == 0) { : *retval = thd->exitval; : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } :} : :APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd) :{ : apr_status_t stat; : :#ifdef PTHREAD_DETACH_ARG1_ADDR : if ((stat = pthread_detach(thd->td)) == 0) { :#else : if ((stat = pthread_detach(*thd->td)) == 0) { :#endif : : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } :} : :void apr_thread_yield() :{ :} : :APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, : apr_thread_t *thread) :{ : return apr_pool_userdata_get(data, key, thread->pool); :} : :APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, : apr_status_t (*cleanup)(void *), : apr_thread_t *thread) :{ : return apr_pool_userdata_set(data, key, cleanup, thread->pool); :} : :APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, : apr_thread_t *thd) :{ : *thethd = thd->td; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, : apr_os_thread_t *thethd, : apr_pool_t *pool) :{ : if (pool == NULL) { : return APR_ENOPOOL; : } : : if ((*thd) == NULL) { : (*thd) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); : (*thd)->pool = pool; : } : : (*thd)->td = thethd; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, : apr_pool_t *p) :{ : static const pthread_once_t once_init = PTHREAD_ONCE_INIT; : : *control = apr_palloc(p, sizeof(**control)); : (*control)->once = once_init; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, : void (*func)(void)) :{ : return pthread_once(&control->once, func); :} : :APR_POOL_IMPLEMENT_ACCESSOR(thread) : :#endif /* HAVE_PTHREAD_H */ :#endif /* APR_HAS_THREADS */ : :#if !APR_HAS_THREADS : :/* avoid warning for no prototype */ :APR_DECLARE(apr_status_t) apr_os_thread_get(void); : :APR_DECLARE(apr_status_t) apr_os_thread_get(void) :{ : return APR_ENOTIMPL; :} : :#endif /* * Total samples for file : "strings/apr_cpystrn.c" * * 1 3.2258 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr.h" :#include "apr_strings.h" :#include "apr_private.h" :#include "apr_lib.h" : :#if APR_HAVE_SYS_TYPES_H :#include :#endif :#if APR_HAVE_STRING_H :#include :#endif :#if APR_HAVE_CTYPE_H :#include :#endif : :/* : * Apache's "replacement" for the strncpy() function. We roll our : * own to implement these specific changes: : * (1) strncpy() doesn't always null terminate and we want it to. : * (2) strncpy() null fills, which is bogus, esp. when copy 8byte : * strings into 8k blocks. : * (3) Instead of returning the pointer to the beginning of : * the destination string, we return a pointer to the : * terminating '\0' to allow us to "check" for truncation : * : * apr_cpystrn() follows the same call structure as strncpy(). : */ : :APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size) 1 3.2258 :{ : : char *d, *end; : : if (dst_size == 0) { /* apr_cpystrn total: 1 3.2258 */ : return (dst); : } : : d = dst; : end = dst + dst_size - 1; : : for (; d < end; ++d, ++src) { : if (!(*d = *src)) { : return (d); : } : } : : *d = '\0'; /* always null terminate */ : : return (d); :} : : :/* : * This function provides a way to parse a generic argument string : * into a standard argv[] form of argument list. It respects the : * usual "whitespace" and quoteing rules. In the future this could : * be expanded to include support for the apr_call_exec command line : * string processing (including converting '+' to ' ' and doing the : * url processing. It does not currently support this function. : * : * token_context: Context from which pool allocations will occur. : * arg_str: Input argument string for conversion to argv[]. : * argv_out: Output location. This is a pointer to an array : * of pointers to strings (ie. &(char *argv[]). : * This value will be allocated from the contexts : * pool and filled in with copies of the tokens : * found during parsing of the arg_str. : */ :APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, : char ***argv_out, : apr_pool_t *token_context) :{ : const char *cp; : const char *ct; : char *cleaned, *dirty; : int escaped; : int isquoted, numargs = 0, argnum; : :#define SKIP_WHITESPACE(cp) \ : for ( ; *cp == ' ' || *cp == '\t'; ) { \ : cp++; \ : }; : :#define CHECK_QUOTATION(cp,isquoted) \ : isquoted = 0; \ : if (*cp == '"') { \ : isquoted = 1; \ : cp++; \ : } \ : else if (*cp == '\'') { \ : isquoted = 2; \ : cp++; \ : } : :/* DETERMINE_NEXTSTRING: : * At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE. : * NULL implies the argument string has been fully traversed. : */ :#define DETERMINE_NEXTSTRING(cp,isquoted) \ : for ( ; *cp != '\0'; cp++) { \ : if ( (isquoted && (*cp == ' ' || *cp == '\t')) \ : || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \ : *(cp+1) == '"' || *(cp+1) == '\''))) { \ : cp++; \ : continue; \ : } \ : if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ : || (isquoted == 1 && *cp == '"') \ : || (isquoted == 2 && *cp == '\'') ) { \ : break; \ : } \ : } : :/* REMOVE_ESCAPE_CHARS: : * Compresses the arg string to remove all of the '\' escape chars. : * The final argv strings should not have any extra escape chars in it. : */ :#define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \ : escaped = 0; \ : while(*dirty) { \ : if (!escaped && *dirty == '\\') { \ : escaped = 1; \ : } \ : else { \ : escaped = 0; \ : *cleaned++ = *dirty; \ : } \ : ++dirty; \ : } \ : *cleaned = 0; /* last line of macro... */ : : cp = arg_str; : SKIP_WHITESPACE(cp); : ct = cp; : : /* This is ugly and expensive, but if anyone wants to figure a : * way to support any number of args without counting and : * allocating, please go ahead and change the code. : * : * Must account for the trailing NULL arg. : */ : numargs = 1; : while (*ct != '\0') { : CHECK_QUOTATION(ct, isquoted); : DETERMINE_NEXTSTRING(ct, isquoted); : if (*ct != '\0') { : ct++; : } : numargs++; : SKIP_WHITESPACE(ct); : } : *argv_out = apr_palloc(token_context, numargs * sizeof(char*)); : : /* determine first argument */ : for (argnum = 0; argnum < (numargs-1); argnum++) { : SKIP_WHITESPACE(cp); : CHECK_QUOTATION(cp, isquoted); : ct = cp; : DETERMINE_NEXTSTRING(cp, isquoted); : cp++; : (*argv_out)[argnum] = apr_palloc(token_context, cp - ct); : apr_cpystrn((*argv_out)[argnum], ct, cp - ct); : cleaned = dirty = (*argv_out)[argnum]; : REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped); : } : (*argv_out)[argnum] = NULL; : : return APR_SUCCESS; :} : :/* Filepath_name_get returns the final element of the pathname. : * Using the current platform's filename syntax. : * "/foo/bar/gum" -> "gum" : * "/foo/bar/gum/" -> "" : * "gum" -> "gum" : * "wi\\n32\\stuff" -> "stuff : * : * Corrected Win32 to accept "a/b\\stuff", "a:stuff" : */ : :APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname) :{ : const char path_separator = '/'; : const char *s = strrchr(pathname, path_separator); : :#ifdef WIN32 : const char path_separator_win = '\\'; : const char drive_separator_win = ':'; : const char *s2 = strrchr(pathname, path_separator_win); : : if (s2 > s) s = s2; : : if (!s) s = strrchr(pathname, drive_separator_win); :#endif : : return s ? ++s : pathname; :} : :/* length of dest assumed >= length of src : * collapse in place (src == dest) is legal. : * returns terminating null ptr to dest string. : */ :APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src) :{ : while (*src) { : if (!apr_isspace(*src)) : *dest++ = *src; : ++src; : } : *dest = 0; : return (dest); :} : :#if !APR_HAVE_STRDUP :char *strdup(const char *str) :{ : char *sdup; : size_t len = strlen(str) + 1; : : sdup = (char *) malloc(len); : memcpy(sdup, str, len); : : return sdup; :} :#endif : :/* The following two routines were donated for SVR4 by Andreas Vogel */ :#if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP) :int strcasecmp(const char *a, const char *b) :{ : const char *p = a; : const char *q = b; : for (p = a, q = b; *p && *q; p++, q++) { : int diff = apr_tolower(*p) - apr_tolower(*q); : if (diff) : return diff; : } : if (*p) : return 1; /* p was longer than q */ : if (*q) : return -1; /* p was shorter than q */ : return 0; /* Exact match */ :} : :#endif : :#if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP) :int strncasecmp(const char *a, const char *b, size_t n) :{ : const char *p = a; : const char *q = b; : : for (p = a, q = b; /*NOTHING */ ; p++, q++) { : int diff; : if (p == a + n) : return 0; /* Match up to n characters */ : if (!(*p && *q)) : return *p - *q; : diff = apr_tolower(*p) - apr_tolower(*q); : if (diff) : return diff; : } : /*NOTREACHED */ :} :#endif : :/* The following routine was donated for UTS21 by dwd@bell-labs.com */ :#if (!APR_HAVE_STRSTR) :char *strstr(char *s1, char *s2) :{ : char *p1, *p2; : if (*s2 == '\0') { : /* an empty s2 */ : return(s1); : } : while((s1 = strchr(s1, *s2)) != NULL) { : /* found first character of s2, see if the rest matches */ : p1 = s1; : p2 = s2; : while (*++p1 == *++p2) { : if (*p1 == '\0') { : /* both strings ended together */ : return(s1); : } : } : if (*p2 == '\0') { : /* second string ended, a match */ : break; : } : /* didn't find a match here, try starting at next character in s1 */ : s1++; : } : return(s1); :} :#endif : /* * Total samples for file : "locks/unix/thread_rwlock.c" * * 1 3.2258 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr_arch_thread_rwlock.h" :#include "apr_private.h" : :#if APR_HAS_THREADS : :#ifdef HAVE_PTHREAD_RWLOCKS : :/* The rwlock must be initialized but not locked by any thread when : * cleanup is called. */ :static apr_status_t thread_rwlock_cleanup(void *data) :{ : apr_thread_rwlock_t *rwlock = (apr_thread_rwlock_t *)data; : apr_status_t stat; : : stat = pthread_rwlock_destroy(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, : apr_pool_t *pool) :{ : apr_thread_rwlock_t *new_rwlock; : apr_status_t stat; : : new_rwlock = apr_palloc(pool, sizeof(apr_thread_rwlock_t)); : new_rwlock->pool = pool; : : if ((stat = pthread_rwlock_init(&new_rwlock->rwlock, NULL))) { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : return stat; : } : : apr_pool_cleanup_register(new_rwlock->pool, : (void *)new_rwlock, thread_rwlock_cleanup, : apr_pool_cleanup_null); : : *rwlock = new_rwlock; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : : stat = pthread_rwlock_rdlock(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : : stat = pthread_rwlock_tryrdlock(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : /* Normalize the return code. */ : if (stat == EBUSY) : stat = APR_EBUSY; : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : 1 3.2258 : stat = pthread_rwlock_wrlock(&rwlock->rwlock); /* apr_thread_rwlock_wrlock total: 1 3.2258 */ :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : : stat = pthread_rwlock_trywrlock(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : /* Normalize the return code. */ : if (stat == EBUSY) : stat = APR_EBUSY; : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : : stat = pthread_rwlock_unlock(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) :{ : return apr_pool_cleanup_run(rwlock->pool, rwlock, thread_rwlock_cleanup); :} : :#else /* HAVE_PTHREAD_RWLOCKS */ : :APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, : apr_pool_t *pool) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :#endif /* HAVE_PTHREAD_RWLOCKS */ :APR_POOL_IMPLEMENT_ACCESSOR(thread_rwlock) : :#endif /* APR_HAS_THREADS */ /* * Total samples for file : "locks/unix/thread_cond.c" * * 1 3.2258 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr.h" : :#if APR_HAS_THREADS : :#include "apr_arch_thread_mutex.h" :#include "apr_arch_thread_cond.h" : :static apr_status_t thread_cond_cleanup(void *data) :{ : apr_thread_cond_t *cond = (apr_thread_cond_t *)data; : apr_status_t rv; : : rv = pthread_cond_destroy(&cond->cond); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, : apr_pool_t *pool) :{ : apr_thread_cond_t *new_cond; : apr_status_t rv; : : new_cond = apr_palloc(pool, sizeof(apr_thread_cond_t)); : : new_cond->pool = pool; : : if ((rv = pthread_cond_init(&new_cond->cond, NULL))) { :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return rv; : } : : apr_pool_cleanup_register(new_cond->pool, : (void *)new_cond, thread_cond_cleanup, : apr_pool_cleanup_null); : : *cond = new_cond; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, : apr_thread_mutex_t *mutex) :{ : apr_status_t rv; : : rv = pthread_cond_wait(&cond->cond, &mutex->mutex); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, : apr_thread_mutex_t *mutex, : apr_interval_time_t timeout) :{ : apr_status_t rv; : apr_time_t then; : struct timespec abstime; : : then = apr_time_now() + timeout; : abstime.tv_sec = apr_time_sec(then); : abstime.tv_nsec = apr_time_usec(then) * 1000; /* nanoseconds */ : : rv = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &abstime); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : if (ETIMEDOUT == rv) { : return APR_TIMEUP; : } : return rv; :} : : :APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) :{ : apr_status_t rv; : 1 3.2258 : rv = pthread_cond_signal(&cond->cond); /* apr_thread_cond_signal total: 1 3.2258 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) :{ : apr_status_t rv; : : rv = pthread_cond_broadcast(&cond->cond); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) :{ : return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); :} : :APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) : :#endif /* APR_HAS_THREADS */ /* * Total samples for file : "dso/unix/dso.c" * * 1 3.2258 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed under the Apache License, Version 2.0 (the "License"); : * you may not use this file except in compliance with the License. : * You may obtain a copy of the License at : * : * http://www.apache.org/licenses/LICENSE-2.0 : * : * Unless required by applicable law or agreed to in writing, software : * distributed under the License is distributed on an "AS IS" BASIS, : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : * See the License for the specific language governing permissions and : * limitations under the License. : */ : :#include "apr_arch_dso.h" :#include "apr_strings.h" :#include "apr_portable.h" : :#if APR_HAS_DSO : :#if !defined(DSO_USE_DLFCN) && !defined(DSO_USE_SHL) && !defined(DSO_USE_DYLD) :#error No DSO implementation specified. :#endif : :#ifdef HAVE_STDDEF_H :#include :#endif :#if APR_HAVE_STDLIB_H :#include /* malloc(), free() */ :#endif :#if APR_HAVE_STRING_H :#include /* for strerror() on HP-UX */ :#endif : :#if defined(DSO_USE_DYLD) :#define DYLD_LIBRARY_HANDLE (void *)-1 :#endif : :APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, : apr_os_dso_handle_t osdso, : apr_pool_t *pool) :{ : *aprdso = apr_pcalloc(pool, sizeof **aprdso); : (*aprdso)->handle = osdso; : (*aprdso)->pool = pool; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, : apr_dso_handle_t *aprdso) :{ : *osdso = aprdso->handle; : return APR_SUCCESS; :} : :static apr_status_t dso_cleanup(void *thedso) :{ : apr_dso_handle_t *dso = thedso; : : if (dso->handle == NULL) : return APR_SUCCESS; : :#if defined(DSO_USE_SHL) : shl_unload((shl_t)dso->handle); :#elif defined(DSO_USE_DYLD) : if (dso->handle != DYLD_LIBRARY_HANDLE) { : NSUnLinkModule(dso->handle, FALSE); : } :#elif defined(DSO_USE_DLFCN) : if (dlclose(dso->handle) != 0) : return APR_EINIT; :#endif : dso->handle = NULL; : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, : const char *path, apr_pool_t *pool) :{ :#if defined(DSO_USE_SHL) : shl_t os_handle = shl_load(path, BIND_IMMEDIATE, 0L); : :#elif defined(DSO_USE_DYLD) : NSObjectFileImage image; : NSModule os_handle = NULL; : NSObjectFileImageReturnCode dsoerr; : const char* err_msg = NULL; : dsoerr = NSCreateObjectFileImageFromFile(path, &image); : : if (dsoerr == NSObjectFileImageSuccess) { :#if defined(NSLINKMODULE_OPTION_RETURN_ON_ERROR) && defined(NSLINKMODULE_OPTION_NONE) : os_handle = NSLinkModule(image, path, : NSLINKMODULE_OPTION_RETURN_ON_ERROR | : NSLINKMODULE_OPTION_NONE); : /* If something went wrong, get the errors... */ : if (!os_handle) { : NSLinkEditErrors errors; : int errorNumber; : const char *fileName; : NSLinkEditError(&errors, &errorNumber, &fileName, &err_msg); : } :#else : os_handle = NSLinkModule(image, path, FALSE); :#endif : NSDestroyObjectFileImage(image); : } : else if ((dsoerr == NSObjectFileImageFormat || : dsoerr == NSObjectFileImageInappropriateFile) && : NSAddLibrary(path) == TRUE) { : os_handle = (NSModule)DYLD_LIBRARY_HANDLE; : } : else { : err_msg = "cannot create object file image or add library"; : } : :#elif defined(DSO_USE_DLFCN) :#if defined(OSF1) || defined(SEQUENT) || defined(SNI) ||\ : (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) ||\ : defined(__DragonFly__) : void *os_handle = dlopen((char *)path, RTLD_NOW | RTLD_GLOBAL); : :#else : int flags = RTLD_NOW | RTLD_GLOBAL; : void *os_handle; :#ifdef _AIX : if (strchr(path + 1, '(') && path[strlen(path) - 1] == ')') : { : /* This special archive.a(dso.so) syntax is required for : * the way libtool likes to build shared libraries on AIX. : * dlopen() support for such a library requires that the : * RTLD_MEMBER flag be enabled. : */ : flags |= RTLD_MEMBER; : } :#endif : os_handle = dlopen(path, flags); :#endif :#endif /* DSO_USE_x */ : : *res_handle = apr_pcalloc(pool, sizeof(**res_handle)); : : if(os_handle == NULL) { :#if defined(DSO_USE_SHL) : (*res_handle)->errormsg = strerror(errno); : return APR_EDSOOPEN; :#elif defined(DSO_USE_DYLD) : (*res_handle)->errormsg = (err_msg) ? err_msg : "link failed"; : return APR_EDSOOPEN; :#elif defined(DSO_USE_DLFCN) : (*res_handle)->errormsg = dlerror(); : return APR_EDSOOPEN; :#endif : } : : (*res_handle)->handle = (void*)os_handle; : (*res_handle)->pool = pool; : (*res_handle)->errormsg = NULL; : : apr_pool_cleanup_register(pool, *res_handle, dso_cleanup, apr_pool_cleanup_null); : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) :{ : return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup); :} : :APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, : apr_dso_handle_t *handle, : const char *symname) 1 3.2258 :{ /* apr_dso_sym total: 1 3.2258 */ :#if defined(DSO_USE_SHL) : void *symaddr = NULL; : int status; : : errno = 0; : status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_PROCEDURE, &symaddr); : if (status == -1 && errno == 0) /* try TYPE_DATA instead */ : status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_DATA, &symaddr); : if (status == -1) : return APR_ESYMNOTFOUND; : *ressym = symaddr; : return APR_SUCCESS; : :#elif defined(DSO_USE_DYLD) : void *retval = NULL; : NSSymbol symbol; : char *symname2 = (char*)malloc(sizeof(char)*(strlen(symname)+2)); : sprintf(symname2, "_%s", symname); :#ifdef NSLINKMODULE_OPTION_PRIVATE : if (handle->handle == DYLD_LIBRARY_HANDLE) { : symbol = NSLookupAndBindSymbol(symname2); : } : else { : symbol = NSLookupSymbolInModule((NSModule)handle->handle, symname2); : } :#else : symbol = NSLookupAndBindSymbol(symname2); :#endif : free(symname2); : if (symbol == NULL) { : handle->errormsg = "undefined symbol"; : return APR_ESYMNOTFOUND; : } : retval = NSAddressOfSymbol(symbol); : if (retval == NULL) { : handle->errormsg = "cannot resolve symbol"; : return APR_ESYMNOTFOUND; : } : *ressym = retval; : return APR_SUCCESS; :#elif defined(DSO_USE_DLFCN) : :#if defined(DLSYM_NEEDS_UNDERSCORE) : void *retval; : char *symbol = (char*)malloc(sizeof(char)*(strlen(symname)+2)); : sprintf(symbol, "_%s", symname); : retval = dlsym(handle->handle, symbol); : free(symbol); :#elif defined(SEQUENT) || defined(SNI) : void *retval = dlsym(handle->handle, (char *)symname); :#else : void *retval = dlsym(handle->handle, symname); :#endif /* DLSYM_NEEDS_UNDERSCORE */ : : if (retval == NULL) { : handle->errormsg = dlerror(); : return APR_ESYMNOTFOUND; : } : : *ressym = retval; : : return APR_SUCCESS; :#endif /* DSO_USE_x */ :} : :APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, : apr_size_t buflen) :{ : if (dso->errormsg) { : apr_cpystrn(buffer, dso->errormsg, buflen); : return dso->errormsg; : } : return "No Error"; :} : :#endif