Original geschrieben von amiga
[...] Wir können den Pthread beenden ohne dass die Verbindung beendet wird. Aufräumarbeiten werden von einem Thread erledigt, der mit pthread_cond_wait auf "User-Verlässt-Chat"-Signale wartet.[...]
So in der Art hatt ich's mir auch gedacht. (mit nen garbage collecting thread, dem die anderen threads sagen wenn sie sterben)
[QUOTE]Original geschrieben von amiga
[...]Das Problem ist nur, dass irgendwann die Filedeskriptoren knapp werden könnten dann hat man eigentlich keine andere wahl, als einen neuen Prozess als FileDescriptor-Container zu forken bis jetzt sind wir aber immer mit den FDs ausgekommen [...][/QUOTE
Ich glaub der Fall ist mir mal wurscht.
Nur ein problem gibt's, für das ich eine (halbwegs unschöne) Lösung hab:
Die Struktur fd_set, welche von select() gebraucht wird, hat per default eine begrenzung auf 64 FDs. Man kann mit nen Makro eine größere Anzahl definieren, aber das ist alles irgendwie sehr undynamisch. Denn wieviel nehm ich? Will das meine fd_set Struktur "atmen" kann.
Hab mir dazu ne Struktur xfd_set überlegt, die man auch per dem Makro xfd_set_fd_set(xfd_set*) zu fd_set* casten kann.
Für diese Struktur hab ich Funktionen geschrieben, die das Array dynamisch mit realloc() u.d.G. anpassen kann. (Boundaries werden natürlich auch gechecked.)
Hab's noch nicht getestet / ausprobiert, aber hier ist mal der vorläufige Code:
xfd_set.h
Code:
#include <sys/param.h>
#include <sys/types.h>
typedef unsigned short masksize_t;
/* xfd_set_data can be casted to fd_set
without any problems, I hope... */
typedef struct xfd_set_data_s {
fd_mask * fd_bits;
} xfd_set_data;
typedef struct xfd_set_s {
xfd_set_data data;
masksize_t masks;
} xfd_set;
/* usage:
======
xfd_set set;
struct timeval timeout;
xfd_set_init( &set );
timeout.tv_sec = 5;
timeout.tv_usec = 0;
// <verion_1>
xfd_set_set( &set, stdin );
// ...
// call xfd_set_resize() when xfd_set_set() == EINVAL
// check for: xfd_set_resize() == ENOMEM !!
if( select( xfd_set_maxfd( &set ) + 1, xfd_set_fd_set( &set ), NULL, NULL, &timeout ) < 0 ) {
// handle error ...
}
else {
// read ...
}
// </version_1>
// <verion_2>
int maxfd = -1;
xfd_set_setmax( &set, stdin, &maxfd );
// ...
// call xfd_set_resize() when xfd_set_setmax() == EINVAL
// check for: xfd_set_resize() == ENOMEM !!
if( select( maxfd + 1, xfd_set_fd_set( &set ), NULL, NULL, &timeout ) < 0 ) {
// handle error ...
}
else {
// read ...
}
// </version_2>
// <verion_3>
int maxfd = -1;
xfd_set_xsetmax( &set, stdin, &maxfd );
// ...
// check for: xfd_set_xsetmax() == ENOMEM !!
// no xfd_set_resize() is required here.
if( select( maxfd + 1, xfd_set_fd_set( &set ), NULL, NULL, &timeout ) < 0 ) {
// handle error ...
}
else {
// read ...
}
// </version_3>
xfd_set_destroy( &set );
*/
/*
TODO:
Überlegen, ob ich die Funktionen, die sowieso immer 0 retunieren, nicht void mache:
xfd_set_destroy(), xfd_set_clearall()
*/
/* return values: */
int xfd_set_init ( xfd_set * set ); /* 0, ENOMEM */
int xfd_set_destroy ( xfd_set * set ); /* 0 */
int xfd_set_set ( xfd_set * set, int fd ); /* 0, EINVAL */
int xfd_set_setmax ( xfd_set * set, int fd, int * maxfd ); /* 0, EINVAL */
int xfd_set_xset ( xfd_set * set, int fd ); /* 0, ENOMEM */
int xfd_set_xsetmax ( xfd_set * set, int fd, int * maxfd ); /* 0, ENOMEM */
int xfd_set_clear ( xfd_set * set, int fd ); /* 0, EINVAL */
int xfd_set_clearall( xfd_set * set ); /* 0 */
int xfd_set_isset ( const xfd_set * set, int fd ); /* 0, 1 */
int xfd_set_fdmax ( const xfd_set * set ); /* fdmax */
int xfd_set_copy ( const xfd_set * set, xfd_set * dest ); /* 0, ENOMEM */
int xfd_set_resize ( xfd_set * set, masksize_t masks ); /* 0, ENOMEM */
int xfd_set_pack ( xfd_set * set ); /* 0, ENOMEM */
#define xfd_set_fd_set( set ) ((fd_set*)&((set)->data))
#define xfd_set_inrange( set, fd ) (((fd)/NFDBITS) < (set)->masks)
xfd_set.c
Code:
#include "xfd_set.h"
int xfd_set_init( xfd_set * set ) {
size_t memsize = (set->masks = howmany(FD_SETSIZE, NFDBITS)) * sizeof(fd_mask);
set->data.fd_bits = malloc( memsize );
if( set.data->fd_bits ) {
memset( set->data.fd_bits, 0, memsize );
return 0;
}
else {
return ENOMEM;
}
}
int xfd_set_destroy( xfd_set * set ) {
free( set->data.fd_bits );
/*
set->data.fd_bits = NULL;
set->masks = 0;
*/
return 0;
}
int xfd_set_set( xfd_set * set, int fd ) {
if( xfd_set_inrange( set, fd ) ) {
FD_SET( fd, xfd_set_fd_set( set ) );
return 0;
}
else {
return EINVAL;
}
}
int xfd_set_setmax( xfd_set * set, int fd, int * maxfd ) {
int errnum = xfd_set_set( set, fd );
if( errnum == 0 ) {
*maxfd = MAX( *maxfd, fd );
}
return errnum;
}
int xfd_set_xset( xfd_set * set, int fd ) {
if( xfd_set_inrange( set, fd ) ) {
FD_SET( fd, xfd_set_fd_set( set ) );
return 0;
}
else {
int errnum = xfd_set_resize( set, set->masks + 1 );
if( errnum == 0 ) {
FD_SET( fd, xfd_set_fd_set( set ) );
}
return errnum;
}
}
int xfd_set_xsetmax( xfd_set * set, int fd, int * maxfd ) {
int errnum = xfd_set_xset( set, fd );
if( errnum == 0 ) {
*maxfd = MAX( *maxfd, fd );
}
return errnum;
}
int xfd_set_clear( xfd_set * set, int fd ) {
if( xfd_set_inrange( set, fd ) ) {
FD_CLR( fd, xfd_set_fd_set( set ) );
return 0;
}
else {
return EINVAL;
}
}
int xfd_set_clearall( xfd_set * set ) {
memset( set->data.fd_bits, 0, set->masks * sizeof(fd_mask) );
return 0;
}
int xfd_set_isset( const xfd_set * set, int fd ) {
if( xfd_set_inrange( set, fd ) ) {
return FD_ISSET( fd, xfd_set_fd_set( set ) );
}
else {
return 0;
}
}
/* TODO: Test this! */
int xfd_set_fdmax( const xfd_set * set ) {
int fdmax = -1;
masksize_t i = set->masks;
while( i > 0 ) {
if( set->data.fd_bits[ -- i ] )
break;
}
if( i > 0 ) {
fd_mask mask = set->data.fd_bits[ i ];
fdmax = NFDBITS * i - 1;
while( mask ) {
mask >>= 1;
++ fdmax;
}
}
return fdmax;
}
int xfd_set_copy( const xfd_set * set, xfd_set * dest ) {
size_t memsize = set->masks * sizeof(fd_mask);
fd_mask * fd_bits = malloc( memsize );
if( fd_bits ) {
dest->masks = set->masks;
memcpy( dest->data.fd_bits, set->data.fd_bits, memsize );
return 0;
}
else {
return ENOMEM;
}
}
int xfd_set_resize( xfd_set * set, masksize_t masks ) {
fd_mask * fd_bits = realloc( set->data.fd_bits, masks * sizeof(fd_mask) );
if( fd_bits ) {
if( masks > set->masks ) {
memset( &fd_bits[ set->masks ], 0, masks - set->masks );
}
set->data.fd_bits = fd_bits;
set->masks = masks;
return 0;
}
else {
return ENOMEM;
}
}
int xfd_set_pack( xfd_set * set ) {
masksize_t masks = set->masks;
fd_mask * fd_bits = NULL;
while( masks > 0 ) {
if( set->data.fd_bits[ -- masks ] )
break;
}
fd_bits = realloc( set->data.fd_bits, (++ masks) * sizeof(fd_mask) );
if( fd_bits ) {
set->data.fd_bits = fd_bits;
set->masks = masks;
return 0;
}
else {
return ENOMEM;
}
}
Lesezeichen