1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

use libco instead of state-thread(st), still have some bug

This commit is contained in:
xiaozhihong 2020-02-16 21:07:54 +08:00
parent 51d6c367f5
commit 7c8a35aea9
88 changed files with 4836 additions and 19273 deletions

View file

@ -1,91 +0,0 @@
#
# Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Silicon Graphics, Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
CC = cc
SHELL = /bin/sh
ECHO = /bin/echo
DEPTH = ..
BUILD =
TARGETDIR = obj
DEFINES =
OTHER_FLAGS =
CFLAGS =
OBJDIR = $(DEPTH)/$(TARGETDIR)
INCDIR = $(DEPTH)/$(TARGETDIR)
LIBRESOLV =
EXTRALIBS =
SLIBRARY = $(OBJDIR)/libstx.a
OBJS = $(OBJDIR)/dnscache.o $(OBJDIR)/dnsres.o $(OBJDIR)/lrucache.o
CFLAGS += -Wall -I$(INCDIR)
AR = ar
ARFLAGS = rv
RANLIB = ranlib
##########################
# Platform section.
#
ifeq (LINUX, $(findstring LINUX, $(OS)))
LIBRESOLV = -lresolv
endif
ifeq ($(OS), SOLARIS)
LIBRESOLV = -lresolv
EXTRALIBS = -lsocket -lnsl
endif
#
# End of platform section.
##########################
all: $(SLIBRARY)
$(SLIBRARY): $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
$(RANLIB) $@
$(OBJDIR)/%.o: %.c stx.h common.h
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(OBJS) $(SLIBRARY)
#.DEFAULT:
# @cd $(DEPTH); $(MAKE) $@

View file

@ -1,42 +0,0 @@
This directory contains extensions to the core State Threads Library
that were contributed by users. All files hereunder are not part of the
State Threads Library itself. They are provided as-is, without warranty
or support, and under whatever license terms their authors provided. To
contribute your own extensions, just mail them to the project
administrators or to one of the project's mailing lists; see
state-threads.sourceforge.net. Please indicate the license terms under
which the project may distribute your contribution.
========================================================================
stx_fileio
----------
Contributed by Jeff <jlb-st@houseofdistraction.com>, 4 Nov 2002.
Provides non-blocking random access file reading capability for
programs using the State Threads library. There is one public function:
ssize_t stx_file_read(st_netfd_t fd, off_t offset,
void *buf, size_t nbytes, st_utime_t timeout);
The implementation is not optimal in that the data is copied at least once
more than should be necessary. Its usefulness is limited to cases where
random access to a file is required and where starvation of other threads
is unacceptable.
The particular application which motivated this implementation was a UDP
file transfer protocol. Because the OS does very little buffering of UDP
traffic it is important that UDP transmission threads are not starved for
periods of time which are long relative to the interval required to
maintain a steady send rate.
Licensed under the same dual MPL/GPL as core State Threads.
========================================================================
stx_dns
-------
Documentation coming.
========================================================================

View file

@ -1,77 +0,0 @@
#ifndef _STX_COMMON_H_
#define _STX_COMMON_H_
#include <stddef.h>
#include <stdlib.h>
#define STX_BEGIN_MACRO {
#define STX_END_MACRO }
/*****************************************
* Circular linked list definitions
*/
typedef struct _stx_clist {
struct _stx_clist *next;
struct _stx_clist *prev;
} stx_clist_t;
/* Insert element "_e" into the list, before "_l" */
#define STX_CLIST_INSERT_BEFORE(_e,_l) \
STX_BEGIN_MACRO \
(_e)->next = (_l); \
(_e)->prev = (_l)->prev; \
(_l)->prev->next = (_e); \
(_l)->prev = (_e); \
STX_END_MACRO
/* Insert element "_e" into the list, after "_l" */
#define STX_CLIST_INSERT_AFTER(_e,_l) \
STX_BEGIN_MACRO \
(_e)->next = (_l)->next; \
(_e)->prev = (_l); \
(_l)->next->prev = (_e); \
(_l)->next = (_e); \
STX_END_MACRO
/* Append an element "_e" to the end of the list "_l" */
#define STX_CLIST_APPEND_LINK(_e,_l) STX_CLIST_INSERT_BEFORE(_e,_l)
/* Remove the element "_e" from it's circular list */
#define STX_CLIST_REMOVE_LINK(_e) \
STX_BEGIN_MACRO \
(_e)->prev->next = (_e)->next; \
(_e)->next->prev = (_e)->prev; \
STX_END_MACRO
/* Return the head/tail of the list */
#define STX_CLIST_HEAD(_l) (_l)->next
#define STX_CLIST_TAIL(_l) (_l)->prev
/* Return non-zero if the given circular list "_l" is empty, */
/* zero if the circular list is not empty */
#define STX_CLIST_IS_EMPTY(_l) \
((_l)->next == (_l))
/* Initialize a circular list */
#define STX_CLIST_INIT_CLIST(_l) \
STX_BEGIN_MACRO \
(_l)->next = (_l); \
(_l)->prev = (_l); \
STX_END_MACRO
/*****************************************
* Useful macros
*/
#ifndef offsetof
#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier))
#endif
#define STX_MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif /* !_STX_COMMON_H_ */

View file

@ -1,190 +0,0 @@
#include "stx.h"
#include "common.h"
/*****************************************
* Basic types definitions
*/
typedef struct _stx_dns_data {
struct in_addr *addrs;
int num_addrs;
int cur;
time_t expires;
} stx_dns_data_t;
#define MAX_HOST_ADDRS 1024
static struct in_addr addr_list[MAX_HOST_ADDRS];
stx_cache_t *_stx_dns_cache = NULL;
extern int _stx_dns_ttl;
extern int _stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout);
static unsigned long hash_hostname(const void *key)
{
const char *name = (const char *)key;
unsigned long hash = 0;
while (*name)
hash = (hash << 4) - hash + *name++; /* hash = hash * 15 + *name++ */
return hash;
}
static void cleanup_entry(void *key, void *data)
{
if (key)
free(key);
if (data) {
if (((stx_dns_data_t *)data)->addrs)
free(((stx_dns_data_t *)data)->addrs);
free(data);
}
}
static int lookup_entry(const char *host, struct in_addr *addrs,
int *num_addrs, int rotate)
{
stx_cache_entry_t *entry;
stx_dns_data_t *data;
int n;
entry = stx_cache_entry_lookup(_stx_dns_cache, host);
if (entry) {
data = (stx_dns_data_t *)stx_cache_entry_getdata(entry);
if (st_time() <= data->expires) {
if (*num_addrs == 1) {
if (rotate) {
*addrs = data->addrs[data->cur++];
if (data->cur >= data->num_addrs)
data->cur = 0;
} else {
*addrs = data->addrs[0];
}
} else {
n = STX_MIN(*num_addrs, data->num_addrs);
memcpy(addrs, data->addrs, n * sizeof(*addrs));
*num_addrs = n;
}
stx_cache_entry_release(_stx_dns_cache, entry);
return 1;
}
/*
* Cache entry expired: decrement its refcount and purge it from cache.
*/
stx_cache_entry_release(_stx_dns_cache, entry);
stx_cache_entry_delete(_stx_dns_cache, entry);
}
return 0;
}
static void insert_entry(const char *host, struct in_addr *addrs, int count)
{
stx_cache_entry_t *entry;
stx_dns_data_t *data;
char *key;
size_t n;
if (_stx_dns_ttl > 0) {
key = strdup(host);
data = (stx_dns_data_t *)malloc(sizeof(stx_dns_data_t));
n = count * sizeof(*addrs);
if (data) {
data->addrs = (struct in_addr *)malloc(n);
if (data->addrs)
memcpy(data->addrs, addrs, n);
data->num_addrs = count;
data->cur = 0;
data->expires = st_time() + _stx_dns_ttl;
}
entry = stx_cache_entry_create(key, data, strlen(host) + 1 +
sizeof(stx_dns_data_t) + n +
stx_cache_entry_sizeof());
if (key && data && data->addrs && entry &&
stx_cache_entry_insert(_stx_dns_cache, entry) == 0) {
stx_cache_entry_release(_stx_dns_cache, entry);
return;
}
if (entry)
stx_cache_entry_delete(_stx_dns_cache, entry);
else
cleanup_entry(key, data);
}
}
int _stx_dns_cache_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout,
int rotate)
{
char host[128];
int n, count;
if (!_stx_dns_cache)
return _stx_dns_getaddrlist(hostname, addrs, num_addrs, timeout);
for (n = 0; n < sizeof(host) - 1 && hostname[n]; n++) {
host[n] = tolower(hostname[n]);
}
host[n] = '\0';
if (lookup_entry(host, addrs, num_addrs, rotate))
return 0;
count = MAX_HOST_ADDRS;
if (_stx_dns_getaddrlist(host, addr_list, &count, timeout) < 0)
return -1;
n = STX_MIN(*num_addrs, count);
memcpy(addrs, addr_list, n * sizeof(*addrs));
*num_addrs = n;
insert_entry(host, addr_list, count);
return 0;
}
int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size)
{
_stx_dns_cache = stx_cache_create(max_size, max_bytes, hash_size,
hash_hostname,
(long (*)(const void *, const void *))strcmp,
cleanup_entry);
if (!_stx_dns_cache)
return -1;
return 0;
}
void stx_dns_cache_getinfo(stx_cache_info_t *info)
{
if (_stx_dns_cache)
stx_cache_getinfo(_stx_dns_cache, info);
else
memset(info, 0, sizeof(stx_cache_info_t));
}
int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout)
{
return _stx_dns_cache_getaddrlist(hostname, addrs, num_addrs, timeout, 0);
}
int stx_dns_getaddr(const char *hostname, struct in_addr *addr,
st_utime_t timeout)
{
int n = 1;
return _stx_dns_cache_getaddrlist(hostname, addr, &n, timeout, 1);
}

View file

@ -1,305 +0,0 @@
/*
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Silicon Graphics, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stx.h"
#define MAXPACKET 1024
#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
#define NETDB_INTERNAL h_NETDB_INTERNAL
#endif
/* New in Solaris 7 */
#if !defined(_getshort) && defined(ns_get16)
#define _getshort(cp) ns_get16(cp)
#define _getlong(cp) ns_get32(cp)
#endif
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf_t;
int _stx_dns_ttl;
static int parse_answer(querybuf_t *ans, int len, struct in_addr *addrs,
int *num_addrs)
{
char buf[MAXPACKET];
HEADER *ahp;
u_char *cp, *eoa;
int type, n, i;
ahp = &ans->hdr;
eoa = ans->buf + len;
cp = ans->buf + sizeof(HEADER);
h_errno = TRY_AGAIN;
_stx_dns_ttl = -1;
i = 0;
while (ahp->qdcount > 0) {
ahp->qdcount--;
cp += dn_skipname(cp, eoa) + QFIXEDSZ;
}
while (ahp->ancount > 0 && cp < eoa && i < *num_addrs) {
ahp->ancount--;
if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0)
return -1;
cp += n;
if (cp + 4 + 4 + 2 >= eoa)
return -1;
type = _getshort(cp);
cp += 4;
if (type == T_A)
_stx_dns_ttl = _getlong(cp);
cp += 4;
n = _getshort(cp);
cp += 2;
if (type == T_A) {
if (n > sizeof(*addrs) || cp + n > eoa)
return -1;
memcpy(&addrs[i++], cp, n);
}
cp += n;
}
*num_addrs = i;
return 0;
}
static int query_domain(st_netfd_t nfd, const char *name,
struct in_addr *addrs, int *num_addrs,
st_utime_t timeout)
{
querybuf_t qbuf;
u_char *buf = qbuf.buf;
HEADER *hp = &qbuf.hdr;
int blen = sizeof(qbuf);
int i, len, id;
for (i = 0; i < _res.nscount; i++) {
len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen);
if (len <= 0) {
h_errno = NO_RECOVERY;
return -1;
}
id = hp->id;
if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]),
sizeof(struct sockaddr), timeout) != len) {
h_errno = NETDB_INTERNAL;
/* EINTR means interrupt by other thread, NOT by a caught signal */
if (errno == EINTR)
return -1;
continue;
}
/* Wait for reply */
do {
len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout);
if (len <= 0)
break;
} while (id != hp->id);
if (len < HFIXEDSZ) {
h_errno = NETDB_INTERNAL;
if (len >= 0)
errno = EMSGSIZE;
else if (errno == EINTR) /* see the comment above */
return -1;
continue;
}
hp->ancount = ntohs(hp->ancount);
hp->qdcount = ntohs(hp->qdcount);
if ((hp->rcode != NOERROR) || (hp->ancount == 0)) {
switch (hp->rcode) {
case NXDOMAIN:
h_errno = HOST_NOT_FOUND;
break;
case SERVFAIL:
h_errno = TRY_AGAIN;
break;
case NOERROR:
h_errno = NO_DATA;
break;
case FORMERR:
case NOTIMP:
case REFUSED:
default:
h_errno = NO_RECOVERY;
}
continue;
}
if (parse_answer(&qbuf, len, addrs, num_addrs) == 0)
return 0;
}
return -1;
}
#define CLOSE_AND_RETURN(ret) \
{ \
n = errno; \
st_netfd_close(nfd); \
errno = n; \
return (ret); \
}
int _stx_dns_getaddrlist(const char *host, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout)
{
char name[MAXDNAME], **domain;
const char *cp;
int s, n, maxlen, dots;
int trailing_dot, tried_as_is;
st_netfd_t nfd;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
return -1;
}
if (_res.options & RES_USEVC) {
h_errno = NETDB_INTERNAL;
errno = ENOSYS;
return -1;
}
if (!host || *host == '\0') {
h_errno = HOST_NOT_FOUND;
return -1;
}
/* Create UDP socket */
if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
h_errno = NETDB_INTERNAL;
return -1;
}
if ((nfd = st_netfd_open_socket(s)) == NULL) {
h_errno = NETDB_INTERNAL;
n = errno;
close(s);
errno = n;
return -1;
}
maxlen = sizeof(name) - 1;
n = 0;
dots = 0;
trailing_dot = 0;
tried_as_is = 0;
for (cp = host; *cp && n < maxlen; cp++) {
dots += (*cp == '.');
name[n++] = *cp;
}
if (name[n - 1] == '.')
trailing_dot = 1;
/*
* If there are dots in the name already, let's just give it a try
* 'as is'. The threshold can be set with the "ndots" option.
*/
if (dots >= _res.ndots) {
if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0)
CLOSE_AND_RETURN(0);
if (h_errno == NETDB_INTERNAL && errno == EINTR)
CLOSE_AND_RETURN(-1);
tried_as_is = 1;
}
/*
* We do at least one level of search if
* - there is no dot and RES_DEFNAME is set, or
* - there is at least one dot, there is no trailing dot,
* and RES_DNSRCH is set.
*/
if ((!dots && (_res.options & RES_DEFNAMES)) ||
(dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
name[n++] = '.';
for (domain = _res.dnsrch; *domain; domain++) {
strncpy(name + n, *domain, maxlen - n);
if (query_domain(nfd, name, addrs, num_addrs, timeout) == 0)
CLOSE_AND_RETURN(0);
if (h_errno == NETDB_INTERNAL && errno == EINTR)
CLOSE_AND_RETURN(-1);
if (!(_res.options & RES_DNSRCH))
break;
}
}
/*
* If we have not already tried the name "as is", do that now.
* note that we do this regardless of how many dots were in the
* name or whether it ends with a dot.
*/
if (!tried_as_is) {
if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0)
CLOSE_AND_RETURN(0);
}
CLOSE_AND_RETURN(-1);
}

View file

@ -1,343 +0,0 @@
#include "stx.h"
#include "common.h"
/*****************************************
* Basic types definitions
*/
struct _stx_centry {
void *key; /* key for doing lookups */
void *data; /* data in the cache */
size_t weight; /* "weight" of this entry */
struct _stx_centry *next; /* next entry */
struct _stx_centry **pthis;
stx_clist_t lru_link; /* for putting this entry on LRU list */
int ref_count; /* use count for this entry */
int delete_pending; /* pending delete flag */
};
struct _stx_cache {
size_t max_size; /* max size of cache */
size_t cur_size; /* current size of cache */
size_t max_weight; /* cache capacity */
size_t cur_weight; /* current total "weight" of all entries */
size_t hash_size; /* size of hash table */
stx_cache_entry_t **table; /* hash table for this cache */
stx_clist_t lru_list; /* least-recently-used list */
/* Cache stats */
unsigned long hits; /* num cache hits */
unsigned long lookups; /* num cache lookups */
unsigned long inserts; /* num inserts */
unsigned long deletes; /* num deletes */
/* Functions */
unsigned long (*key_hash_fn)(const void *);
long (*key_cmp_fn)(const void *, const void *);
void (*cleanup_fn)(void *, void *);
};
#define STX_CACHE_ENTRY_PTR(_qp) \
((stx_cache_entry_t *)((char *)(_qp) - offsetof(stx_cache_entry_t, lru_link)))
/*****************************************
* Cache methods
*/
stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight,
size_t hash_size,
unsigned long (*key_hash_fn)(const void *key),
long (*key_cmp_fn)(const void *key1,
const void *key2),
void (*cleanup_fn)(void *key, void *data))
{
stx_cache_t *newcache;
newcache = (stx_cache_t *)calloc(1, sizeof(stx_cache_t));
if (newcache == NULL)
return NULL;
newcache->table = (stx_cache_entry_t **)calloc(hash_size,
sizeof(stx_cache_entry_t *));
if (newcache->table == NULL) {
free(newcache);
return NULL;
}
newcache->max_size = max_size;
newcache->max_weight = max_weight;
newcache->hash_size = hash_size;
STX_CLIST_INIT_CLIST(&(newcache->lru_list));
newcache->key_hash_fn = key_hash_fn;
newcache->key_cmp_fn = key_cmp_fn;
newcache->cleanup_fn = cleanup_fn;
return newcache;
}
void stx_cache_empty(stx_cache_t *cache)
{
size_t i;
stx_cache_entry_t *entry, *next_entry;
for (i = 0; i < cache->hash_size; i++) {
entry = cache->table[i];
while (entry) {
next_entry = entry->next;
stx_cache_entry_delete(cache, entry);
entry = next_entry;
}
}
}
void stx_cache_traverse(stx_cache_t *cache,
void (*callback)(void *key, void *data))
{
size_t i;
stx_cache_entry_t *entry;
for (i = 0; i < cache->hash_size; i++) {
for (entry = cache->table[i]; entry; entry = entry->next) {
if (!entry->delete_pending)
(*callback)(entry->key, entry->data);
}
}
}
void stx_cache_traverse_lru(stx_cache_t *cache,
void (*callback)(void *key, void *data),
unsigned int n)
{
stx_clist_t *q;
stx_cache_entry_t *entry;
for (q = STX_CLIST_HEAD(&cache->lru_list); q != &cache->lru_list && n;
q = q->next, n--) {
entry = STX_CACHE_ENTRY_PTR(q);
(*callback)(entry->key, entry->data);
}
}
void stx_cache_traverse_mru(stx_cache_t *cache,
void (*callback)(void *key, void *data),
unsigned int n)
{
stx_clist_t *q;
stx_cache_entry_t *entry;
for (q = STX_CLIST_TAIL(&cache->lru_list); q != &cache->lru_list && n;
q = q->prev, n--) {
entry = STX_CACHE_ENTRY_PTR(q);
(*callback)(entry->key, entry->data);
}
}
size_t stx_cache_getsize(stx_cache_t *cache)
{
return cache->cur_size;
}
size_t stx_cache_getweight(stx_cache_t *cache)
{
return cache->cur_weight;
}
void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info)
{
info->max_size = cache->max_size;
info->max_weight = cache->max_weight;
info->hash_size = cache->hash_size;
info->cur_size = cache->cur_size;
info->cur_weight = cache->cur_weight;
info->hits = cache->hits;
info->lookups = cache->lookups;
info->inserts = cache->inserts;
info->deletes = cache->deletes;
}
/*****************************************
* Cache entry methods
*/
stx_cache_entry_t *stx_cache_entry_create(void *key, void *data,
size_t weight)
{
stx_cache_entry_t *newentry;
newentry = (stx_cache_entry_t *)calloc(1, sizeof(stx_cache_entry_t));
if (newentry == NULL)
return NULL;
newentry->key = key;
newentry->data = data;
newentry->weight = weight;
return newentry;
}
void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry)
{
entry->delete_pending = 1;
if (entry->ref_count > 0)
return;
if (entry->pthis) {
*entry->pthis = entry->next;
if (entry->next)
entry->next->pthis = entry->pthis;
cache->cur_size--;
cache->cur_weight -= entry->weight;
cache->deletes++;
STX_CLIST_REMOVE_LINK(&(entry->lru_link));
}
if (cache->cleanup_fn)
cache->cleanup_fn(entry->key, entry->data);
entry->pthis = NULL;
entry->key = NULL;
entry->data = NULL;
free(entry);
}
stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key)
{
unsigned long bucket;
stx_cache_entry_t *entry;
cache->lookups++;
bucket = cache->key_hash_fn(key) % cache->hash_size;
for (entry = cache->table[bucket]; entry; entry = entry->next) {
if (!entry->delete_pending && cache->key_cmp_fn(key, entry->key) == 0)
break;
}
if (entry) {
cache->hits++;
if (entry->ref_count == 0)
STX_CLIST_REMOVE_LINK(&(entry->lru_link));
entry->ref_count++;
}
return entry;
}
void stx_cache_entry_release(stx_cache_t *cache, stx_cache_entry_t *entry)
{
if (entry->ref_count == 0)
return;
entry->ref_count--;
if (entry->ref_count == 0) {
STX_CLIST_APPEND_LINK(&(entry->lru_link), &(cache->lru_list));
if (entry->delete_pending)
stx_cache_entry_delete(cache, entry);
}
}
int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry)
{
stx_cache_entry_t *old_entry;
unsigned long bucket;
/*
* If cache capacity is exceeded, try to remove LRU entries till there is
* enough room or LRU list is empty.
*/
while (cache->cur_weight + entry->weight > cache->max_weight) {
old_entry = stx_cache_entry_getlru(cache);
if (!old_entry) {
/* cache capacity is exceeded and all entries are in use */
return -1;
}
stx_cache_entry_delete(cache, old_entry);
}
/* If cache size is exceeded, remove LRU entry */
if (cache->cur_size >= cache->max_size) {
old_entry = stx_cache_entry_getlru(cache);
if (!old_entry) {
/* cache size is exceeded and all entries are in use */
return -1;
}
stx_cache_entry_delete(cache, old_entry);
}
/* Don't add duplicate entries in the cache */
bucket = cache->key_hash_fn(entry->key) % cache->hash_size;
for (old_entry = cache->table[bucket]; old_entry;
old_entry = old_entry->next) {
if (!old_entry->delete_pending &&
cache->key_cmp_fn(entry->key, old_entry->key) == 0)
break;
}
if (old_entry)
stx_cache_entry_delete(cache, old_entry);
/* Insert in the hash table */
entry->next = cache->table[bucket];
cache->table[bucket] = entry;
entry->pthis = &cache->table[bucket];
if (entry->next)
entry->next->pthis = &entry->next;
entry->ref_count++;
cache->inserts++;
cache->cur_size++;
cache->cur_weight += entry->weight;
return 0;
}
stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache)
{
if (STX_CLIST_IS_EMPTY(&(cache->lru_list)))
return NULL;
return STX_CACHE_ENTRY_PTR(STX_CLIST_HEAD(&(cache->lru_list)));
}
int stx_cache_entry_sizeof(void)
{
return (int)sizeof(stx_cache_entry_t);
}
void *stx_cache_entry_getdata(stx_cache_entry_t *entry)
{
return entry->data;
}
void *stx_cache_entry_getkey(stx_cache_entry_t *entry)
{
return entry->key;
}
size_t stx_cache_entry_getweight(stx_cache_entry_t *entry)
{
return entry->weight;
}

View file

@ -1,367 +0,0 @@
Michael Abd-El-Malek contributed this patch. He wrote:
----------------------------------------
Hello,
This is a patch that enables programmatically dumping the stack of
every thread. This has been useful in debugging deadlocks, etc...
Our usage model is that the SIGUSR2 handler calls the new
_st_print_thread_stacks function, which dumps the stack for all
threads. A convenient feature is that for thread stacks that are the
same (which is common for application with a lot of worker threads
waiting for work), only one stack trace is printed, along with a
count of how many threads have that same stack.
I use the glibc backtrace function to get the backtrace, and then use
popen to execute addr2line and convert memory addresses to file
names, function names, and line numbers. If glibc isn't available,
_st_print_thread_stacks just prints a warning. And this feature is
only available if DEBUG is turned on.
We've found this feature extremely helpful when debugging.
The patch can be a bit more robust (it assumes addr2line exists).
But I didn't want to go through the hassle of doing this, if the
StateThreads community doesn't want to use this patch. (In our
environment, addr2line will always be there.)
Cheers,
Mike
----------------------------------------
Invoking complex functions from a signal handler is not recommended,
plus this patch changes the behavior of existing API hooks. It will
not become part of State Threads proper but you may find it useful
nonetheless. This patch applies to st-1.5.2.
diff -Nur Makefile.1.5.2 Makefile
--- Makefile.1.5.2 Wed Sep 7 14:19:50 2005
+++ Makefile Wed Sep 7 14:33:08 2005
@@ -255,7 +255,8 @@
$(TARGETDIR)/stk.o \
$(TARGETDIR)/sync.o \
$(TARGETDIR)/key.o \
- $(TARGETDIR)/io.o
+ $(TARGETDIR)/io.o \
+ $(TARGETDIR)/backtrace.o
OBJS += $(EXTRA_OBJS)
HEADER = $(TARGETDIR)/st.h
SLIBRARY = $(TARGETDIR)/libst.a
diff -Nur backtrace.c.1.5.2 backtrace.c
--- backtrace.c.1.5.2 Wed Dec 31 16:00:00 1969
+++ backtrace.c Wed Sep 7 13:40:21 2005
@@ -0,0 +1,211 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Contributor(s): Michael Abd-El-Malek (mabdelmalek@cmu.edu)
+ * Carnegie Mellon University
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+
+
+/*
+ * This file contains routines for printing a stack trace of all threads.
+ * Only works when DEBUG is defined and where glibc is available, since it
+ * provides the backtrace() function.
+ */
+
+#define _GNU_SOURCE /* to get program_invocation_name */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#if defined(DEBUG) && defined(__GLIBC__)
+
+#include <errno.h>
+#include "common.h"
+#include <execinfo.h>
+#include <inttypes.h>
+#include <string.h>
+
+
+/* The maximum number of frames to get a stack trace for. If a thread has more
+ * frames than this, then we only show the latest X frames. */
+#define MAX_NUM_FRAMES 64
+
+
+typedef struct thread_stack_s {
+ uint32_t num_frames;
+ void* addresses[MAX_NUM_FRAMES]; /* frame pointers */
+ char* locations[MAX_NUM_FRAMES]; /* file/function/line numbers */
+ uint32_t num_matches;
+
+ struct thread_stack_s* next;
+} thread_stack_t;
+
+static thread_stack_t* stacks = NULL;
+
+
+/* Converts the function's memory addresses to function names, file names, and
+ * line numbers. Calls binutil's addr2line program. */
+static void get_symbol_names(thread_stack_t *stack)
+{
+ char program_to_run[1024], function[256], filename_lineno[256], temp[19];
+ FILE* output;
+ int num_bytes_left;
+ uint32_t i;
+
+ /* Construct the arguments to addr2line */
+ num_bytes_left = sizeof(program_to_run);
+ num_bytes_left -= snprintf(program_to_run, sizeof(program_to_run),
+ "addr2line -fCe %s", program_invocation_name);
+ for (i = 0; i < stack->num_frames && num_bytes_left > 0; ++i) {
+ num_bytes_left -= snprintf(temp, sizeof(temp), " %p", stack->addresses[i]);
+ strncat(program_to_run, temp, num_bytes_left);
+ }
+
+ /* Use popen to execute addr2line and read its ouput */
+ output = popen(program_to_run, "r");
+ for (i = 0; i < stack->num_frames; ++i) {
+ char* function_listing = (char*) malloc(512);
+ fscanf(output, "%255s\n", function);
+ fscanf(output, "%255s\n", filename_lineno);
+ snprintf(function_listing, 512, "%s at %s", function, filename_lineno);
+ stack->locations[i] = function_listing;
+ }
+ pclose(output);
+}
+
+
+static void print_stack(thread_stack_t* stack)
+{
+ int skip_offset = 0, cmp_len;
+ uint32_t i;
+
+ /* Get the function names/filenames/line numbers */
+ get_symbol_names(stack);
+
+ cmp_len = strlen("_st_iterate_threads_helper");
+
+ /* Print the backtrace */
+ for (i = 0; i < stack->num_frames; ++i) {
+ /* Skip frames we don't have location info for */
+ if (!strncmp(stack->locations[i], "??", 2)) {
+ continue;
+ }
+
+ /* Skip the frames that are used for printing the stack trace */
+ if (skip_offset) {
+ printf("\t#%2d %s %p\n", i - skip_offset, stack->locations[i],
+ stack->addresses[i]);
+ } else if (!strncmp(stack->locations[i], "_st_iterate_threads_helper",
+ cmp_len)) {
+ skip_offset = i + 1;
+ }
+ }
+}
+
+
+static void add_current_thread_stack(void)
+{
+ thread_stack_t *new_stack = malloc(sizeof(thread_stack_t));
+ thread_stack_t *search;
+
+ /* Call glibc function to get the backtrace */
+ new_stack->num_frames = backtrace(new_stack->addresses, MAX_NUM_FRAMES);
+
+ /* Check if we have another stacks that is equivalent. If so, then coaelsce
+ * two stacks into one, to minimize output to user. */
+ search = stacks;
+ while (search) {
+ if (search->num_frames == new_stack->num_frames &&
+ !memcmp(search->addresses, new_stack->addresses,
+ search->num_frames * sizeof(void*))) {
+ /* Found an existing stack that is the same as this thread's stack */
+ ++search->num_matches;
+ free(new_stack);
+ return;
+ } else {
+ search = search->next;
+ }
+ }
+
+ /* This is a new stack. Add it to the list of stacks. */
+ new_stack->num_matches = 1;
+ new_stack->next = stacks;
+ stacks = new_stack;
+}
+
+static void print_stack_frames(void)
+{
+ while (stacks) {
+ printf("\n%u thread(s) with this backtrace:\n", stacks->num_matches);
+ print_stack(stacks);
+ stacks = stacks->next;
+ }
+ printf("\n");
+}
+
+static void free_stacks(void)
+{
+ uint32_t i;
+ while (stacks) {
+ thread_stack_t *next = stacks->next;
+ for (i = 0; i < stacks->num_frames; ++i) {
+ free(stacks->locations[i]);
+ }
+ free(stacks);
+ stacks = next;
+ }
+ stacks = NULL;
+}
+
+
+static void st_print_thread_stack(_st_thread_t *thread, int start_flag,
+ int end_flag)
+{
+ if (end_flag == 0) {
+ add_current_thread_stack();
+ } else {
+ print_stack_frames();
+ }
+}
+
+
+void _st_print_thread_stacks(int ignore)
+{
+ _st_iterate_threads_flag = 1;
+ _st_iterate_threads_helper(st_print_thread_stack);
+ _st_iterate_threads_flag = 0;
+
+ /* Deallocate memory */
+ free_stacks();
+}
+
+#else /* defined(DEBUG) && defined(__GLIBC__) */
+
+void _st_print_thread_stacks(int ignore)
+{
+ printf("%s: need DEBUG mode and glibc-specific functions to read stack.\n",
+ __FUNCTION__);
+}
+#endif /* defined(DEBUG) && defined(__GLIBC__) */
diff -Nur common.h.1.5.2 common.h
--- common.h.1.5.2 Wed Sep 7 14:18:37 2005
+++ common.h Wed Sep 7 14:35:36 2005
@@ -371,8 +371,18 @@
*/
#ifdef DEBUG
-void _st_iterate_threads(void);
-#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads()
+typedef void(*_st_func_ptr_t)(_st_thread_t *thread,
+ int start_flag,
+ int end_flag);
+/* Pointer to function that will be called on thread switch */
+extern _st_func_ptr_t _st_iterate_func_ptr;
+extern int _st_iterate_threads_flag;
+/* Thread iteration function that will call an arbitrary function */
+extern void _st_iterate_threads_helper(_st_func_ptr_t func);
+#define ST_DEBUG_ITERATE_THREADS() \
+ if (_st_iterate_func_ptr) { \
+ _st_iterate_threads_helper(_st_iterate_func_ptr); \
+ }
#else
#define ST_DEBUG_ITERATE_THREADS()
#endif
diff -Nur public.h.1.5.2 public.h
--- public.h.1.5.2 Wed Sep 7 11:46:58 2005
+++ public.h Wed Sep 7 13:38:46 2005
@@ -171,8 +171,10 @@
extern st_netfd_t st_open(const char *path, int oflags, mode_t mode);
#ifdef DEBUG
-extern void _st_show_thread_stack(st_thread_t thread, const char *messg);
+extern void _st_show_thread_stack(st_thread_t thread, int start_flag,
+ int end_flag);
extern void _st_iterate_threads(void);
+extern void _st_print_thread_stacks(int ignore);
#endif
#ifdef __cplusplus
diff -Nur sched.c.1.5.2 sched.c
--- sched.c.1.5.2 Wed Sep 7 10:48:05 2005
+++ sched.c Wed Sep 7 13:38:46 2005
@@ -919,16 +919,13 @@
#ifdef DEBUG
-/* ARGSUSED */
-void _st_show_thread_stack(_st_thread_t *thread, const char *messg)
-{
-
-}
-
/* To be set from debugger */
int _st_iterate_threads_flag = 0;
+/* Thread iteration function that will call an arbitrary function */
+_st_func_ptr_t _st_iterate_func_ptr = NULL;
-void _st_iterate_threads(void)
+/* This function iterates over all threads, calling "func" for each thread. */
+void _st_iterate_threads_helper(_st_func_ptr_t func)
{
static _st_thread_t *thread = NULL;
static jmp_buf orig_jb, save_jb;
@@ -944,16 +941,20 @@
if (thread) {
memcpy(thread->context, save_jb, sizeof(jmp_buf));
- _st_show_thread_stack(thread, NULL);
+ func(thread, 0, 0);
} else {
if (MD_SETJMP(orig_jb)) {
_st_iterate_threads_flag = 0;
+ _st_iterate_func_ptr = NULL;
thread = NULL;
- _st_show_thread_stack(thread, "Iteration completed");
+ /* Last thread to iterate through */
+ func(thread, 0, 1);
return;
}
+ /* First thread to iterate through */
thread = _ST_CURRENT_THREAD();
- _st_show_thread_stack(thread, "Iteration started");
+ _st_iterate_func_ptr = func;
+ func(thread, 1, 0);
}
q = thread->tlink.next;
@@ -966,5 +967,17 @@
memcpy(save_jb, thread->context, sizeof(jmp_buf));
MD_LONGJMP(thread->context, 1);
}
+
+/* ARGSUSED */
+void _st_show_thread_stack(_st_thread_t *thread, int start_flag, int end_flag)
+{
+}
+
+/* Iterate over threads inside debugger; see st/README */
+void _st_iterate_threads(void)
+{
+ _st_iterate_threads_helper(_st_show_thread_stack);
+}
+
#endif /* DEBUG */

View file

@ -1,91 +0,0 @@
#ifndef _STX_H_
#define _STX_H_
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <netdb.h>
#include <errno.h>
#include "st.h"
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************
* Basic types definitions
*/
typedef struct _stx_centry stx_cache_entry_t;
typedef struct _stx_cache stx_cache_t;
/* This is public type */
typedef struct _stx_cache_info {
size_t max_size;
size_t max_weight;
size_t hash_size;
size_t cur_size;
size_t cur_weight;
unsigned long hits;
unsigned long lookups;
unsigned long inserts;
unsigned long deletes;
} stx_cache_info_t;
/*****************************************
* Cache and cache entry methods
*/
stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight,
size_t hash_size,
unsigned long (*key_hash_fn)(const void *key),
long (*key_cmp_fn)(const void *key1,
const void *key2),
void (*cleanup_fn)(void *key, void *data));
void stx_cache_empty(stx_cache_t *cache);
void stx_cache_traverse(stx_cache_t *cache,
void (*callback)(void *key, void *data));
void stx_cache_traverse_lru(stx_cache_t *, void (*)(void *, void *),
unsigned int);
void stx_cache_traverse_mru(stx_cache_t *, void (*)(void *, void *),
unsigned int);
void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info);
size_t stx_cache_getsize(stx_cache_t *cache);
size_t stx_cache_getweight(stx_cache_t *cache);
stx_cache_entry_t *stx_cache_entry_create(void *key, void *data,
size_t weight);
void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry);
stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key);
void stx_cache_entry_release(stx_cache_t *, stx_cache_entry_t *);
int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry);
stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache);
int stx_cache_entry_sizeof(void);
void *stx_cache_entry_getdata(stx_cache_entry_t *entry);
void *stx_cache_entry_getkey(stx_cache_entry_t *entry);
size_t stx_cache_entry_getweight(stx_cache_entry_t *entry);
int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size);
void stx_dns_cache_getinfo(stx_cache_info_t *info);
int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout);
int stx_dns_getaddr(const char *hostname, struct in_addr *addr,
st_utime_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* !_STX_H_ */

View file

@ -1,197 +0,0 @@
/*
* File I/O extension to the State Threads Library.
*/
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the file I/O extension to the State Threads Library.
*
* The Initial Developer of the Original Code is Jeff
* <jlb-st@houseofdistraction.com>. Portions created by the Initial
* Developer are Copyright (C) 2002 the Initial Developer. All Rights
* Reserved.
*
* Contributor(s): (none)
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#include <stdlib.h>
#include "stx_fileio.h"
#define STX_FILEIO_SIGNUM SIGUSR2
typedef struct {
st_netfd_t data_fd;
st_netfd_t control_fd;
pid_t pid;
} fileio_data_t;
#define FILEREADER_MAX_READ 1024
typedef struct {
off_t offset;
ssize_t nbytes;
} file_reader_cb_t;
/**
* Fork a process to read a file and return its pid. Receives
* offset/length commands from control stream and sends corresponding data
* to out stream. A zero length on the control stream signals an end.
*
* @param fd stream from which to read
* @param control_out receives the file descriptor to which control commands can be sent
* @param fd_out receives the file descriptor from which the output of the command can be read.
* @return PID of the process created to execute the command
*/
pid_t
file_reader(int fd, int *fd_control, int *fd_out)
{
pid_t pid;
int control_pipe[2], out_pipe[2];
if (pipe(control_pipe) < 0 || pipe(out_pipe) < 0)
return (pid_t)-1;
pid = fork();
if (pid == (pid_t) -1)
{
close(control_pipe[0]);
close(control_pipe[1]);
close(out_pipe[0]);
close(out_pipe[1]);
return pid;
}
else if (pid == (pid_t) 0)
{
// child
off_t pos = 0;
file_reader_cb_t cb;
char buf[FILEREADER_MAX_READ];
if (fd == -1)
_exit(EXIT_FAILURE);
while (sizeof(cb) == read(control_pipe[0], &cb, sizeof(cb))) {
ssize_t nb;
if (0 >= cb.nbytes)
goto clean_exit;
if (pos != cb.offset) {
pos = lseek(fd, cb.offset, SEEK_SET);
if (pos == (off_t)-1)
break;
}
nb = read(fd, buf, cb.nbytes);
if (nb == (ssize_t)-1)
break;
pos += nb;
write(out_pipe[1], (char *)&nb, sizeof(nb));
write(out_pipe[1], buf, nb);
}
perror("ERROR: file_reader: ");
clean_exit:
close(control_pipe[0]);
close(control_pipe[1]);
close(out_pipe[0]);
close(out_pipe[1]);
_exit(EXIT_SUCCESS);
}
// parent
close(out_pipe[1]);
close(control_pipe[0]);
*fd_out = out_pipe[0];
*fd_control = control_pipe[1];
return pid;
}
/**
* fileio_data_t destructor callback
*/
static void
fileio_data_destructor(void *dat_in)
{
if (dat_in) {
fileio_data_t *dat = (fileio_data_t *)dat_in;
file_reader_cb_t cb;
cb.offset = 0;
cb.nbytes = 0;
st_write(dat->control_fd, (char *)&cb, sizeof(cb),
ST_UTIME_NO_TIMEOUT);
waitpid(dat->pid, NULL, 0);
st_netfd_close(dat->control_fd);
st_netfd_close(dat->data_fd);
free(dat_in);
}
}
/**
* Retrieve fileio_data_t struct from an st descriptor. Create and store
* a new one if needed.
*/
static fileio_data_t *get_fileio_data(st_netfd_t fd)
{
fileio_data_t *dat = (fileio_data_t *)st_netfd_getspecific(fd);
if (!dat) {
int fd_control, fd_out;
pid_t pid = file_reader(st_netfd_fileno(fd), &fd_control, &fd_out);
if (pid != (pid_t)-1) {
dat = (fileio_data_t *)calloc(1, sizeof(fileio_data_t));
dat->control_fd = st_netfd_open(fd_control);
dat->data_fd = st_netfd_open(fd_out);
dat->pid = pid;
st_netfd_setspecific(fd, dat, fileio_data_destructor);
}
}
return dat;
}
/**
* Read data from the specified section of a file. Uses a forked
* file_reader process to do the actual reading so as to avoid causing all
* State Threads to block.
*
* @param fd must refer to a seekable file.
* @param offset absolute offset within the file
* @param buf output buffer
* @param nbytes size of the output buffer
* @param timeout
*/
ssize_t
stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout)
{
fileio_data_t *dat = get_fileio_data(fd);
if (dat) {
file_reader_cb_t cb;
ssize_t ret = (ssize_t)-1;
cb.offset = offset;
cb.nbytes = nbytes;
st_write(dat->control_fd, (char *)&cb, sizeof(cb), timeout);
if (sizeof(ret) == st_read(dat->data_fd, (char *)&ret, sizeof(ret), timeout) && 0 < ret && ret <= nbytes) {
return st_read(dat->data_fd, buf, ret, timeout);
} else {
return ret;
}
}
return (ssize_t)-1;
}

View file

@ -1,52 +0,0 @@
/*
* File I/O extension to the State Threads Library.
*/
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the file I/O extension to the State Threads Library.
*
* The Initial Developer of the Original Code is Jeff
* <jlb-st@houseofdistraction.com>. Portions created by the Initial
* Developer are Copyright (C) 2002 the Initial Developer. All Rights
* Reserved.
*
* Contributor(s): (none)
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#ifndef __STX_FILEIO_H__
#define __STX_FILEIO_H__
#include <st.h>
#ifdef __cplusplus
extern "C" {
#endif
extern ssize_t stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* !__STX_FILEIO_H__ */

View file

@ -1,112 +0,0 @@
#include "stx.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_ADDRS 128
#define TIMEOUT (4*1000000LL)
static void do_resolve(const char *host)
{
struct in_addr addrs[MAX_ADDRS];
int i, n = MAX_ADDRS;
if (stx_dns_getaddrlist(host, addrs, &n, TIMEOUT) < 0) {
fprintf(stderr, "stx_dns_getaddrlist: can't resolve %s: ", host);
if (h_errno == NETDB_INTERNAL)
perror("");
else
herror("");
} else {
if (n > 0)
printf("%-40s %s\n", (char *)host, inet_ntoa(addrs[0]));
for (i = 1; i < n; i++)
printf("%-40s %s\n", "", inet_ntoa(addrs[i]));
}
}
static void show_info(void)
{
stx_cache_info_t info;
stx_dns_cache_getinfo(&info);
printf("DNS cache info:\n\n");
printf("max_size: %8d\n", (int)info.max_size);
printf("capacity: %8d bytes\n", (int)info.max_weight);
printf("hash_size: %8d\n", (int)info.hash_size);
printf("cur_size: %8d\n"
"cur_mem: %8d bytes\n"
"hits: %8d\n"
"lookups: %8d\n"
"inserts: %8d\n"
"deletes: %8d\n",
(int)info.cur_size, (int)info.cur_weight, (int)info.hits,
(int)info.lookups, (int)info.inserts, (int)info.deletes);
}
extern stx_cache_t *_stx_dns_cache;
static void printhost(void *host, void *data)
{
printf("%s\n", (char *)host);
}
static void show_lru(void)
{
printf("LRU hosts:\n\n");
stx_cache_traverse_lru(_stx_dns_cache, printhost, 10);
}
static void show_mru(void)
{
printf("MRU hosts:\n\n");
stx_cache_traverse_mru(_stx_dns_cache, printhost, 10);
}
static void flush_cache(void)
{
stx_cache_empty(_stx_dns_cache);
printf("DNS cache is empty\n");
}
int main()
{
char line[256];
char str[sizeof(line)];
st_init();
stx_dns_cache_init(100, 10000, 101);
for ( ; ; ) {
fputs("> ", stdout);
fflush(stdout);
if (!fgets(line, sizeof(line), stdin))
break;
if (sscanf(line, "%s", str) != 1)
continue;
if (strcmp(str, "exit") == 0 || strcmp(str, "quit") == 0)
break;
if (strcmp(str, "info") == 0) {
show_info();
continue;
}
if (strcmp(str, "lru") == 0) {
show_lru();
continue;
}
if (strcmp(str, "mru") == 0) {
show_mru();
continue;
}
if (strcmp(str, "flush") == 0) {
flush_cache();
continue;
}
do_resolve(str);
}
return 0;
}