From: ian Date: Wed, 15 Dec 2004 23:39:47 +0000 (+0000) Subject: many improvements: use Get/SetAssocData for idtables to avoid globals, and adns bindi... X-Git-Tag: debian/1.1.1~115 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-tcl.git;a=commitdiff_plain;h=9b2c18cc9d122b45f9e737864921d32baa599f0c;ds=sidebyside many improvements: use Get/SetAssocData for idtables to avoid globals, and adns bindings are on way to working --- diff --git a/adns/adns.c b/adns/adns.c index 34ca06c..1ecb672 100644 --- a/adns/adns.c +++ b/adns/adns.c @@ -58,10 +58,12 @@ /*---------- important types and forward declarations ----------*/ +typedef struct Query Query; typedef struct Resolver Resolver; typedef struct OptionInfo OptionInfo; static void asynch_check(Resolver *res); static void asynch_sethandlers(Resolver *res, int shutdown); +static void asynch_query_dispose(Tcl_Interp *interp, Query *query); /*---------- common resolver/query option processing ----------*/ @@ -144,8 +146,6 @@ static int parse_options(Tcl_Interp *ip, int objc, Tcl_Obj *const *objv, /*---------- resolver management ----------*/ -IdDataTable adnstcl_resolvers= { "adns-res" }; - struct Resolver { int ix; /* first! */ Tcl_Interp *interp; @@ -202,15 +202,33 @@ static void adnslogfn_callback(adns_state ads, void *logfndata, abort(); /* fixme implement adns_logcallbackfn */ } -int do_adns_destroy_resolver(ClientData cd, Tcl_Interp *ip, void *res_v) { - Resolver *res= res_v; - tabledataid_disposing(res,&adnstcl_resolvers); - if (res->ads) adns_finish(res->ads); +static void destroy_resolver(Tcl_Interp *ip, Resolver *res) { + void *query_v; + adns_query aqu; + + if (res->ads) { + /* although adns would throw these away for us, we need to + * destroy our own data too and only adns has a list of them */ + for (;;) { + adns_forallqueries_begin(res->ads); + aqu= adns_forallqueries_next(res->ads, &query_v); + if (!aqu) break; + asynch_query_dispose(ip, query_v); + } + adns_finish(res->ads); + } asynch_sethandlers(res,1); TFREE(res); - /* fixme what about outstanding queries */ /* fixme what about the default resolver */ - /* fixme what if the tcl interpreter gets deleted */ +} + +static void destroy_resolver_idtabcb(Tcl_Interp *ip, void *resolver_v) { + destroy_resolver(ip,resolver_v); +} + +int do_adns_destroy_resolver(ClientData cd, Tcl_Interp *ip, void *res_v) { + destroy_resolver(ip,res_v); + tabledataid_disposing(ip,res_v,&adnstcl_resolvers); return TCL_OK; } @@ -262,6 +280,10 @@ int do_adns_new_resolver(ClientData cd, Tcl_Interp *ip, return rc; } +const IdDataSpec adnstcl_resolvers= { + "adns-res", "adns-resolvers-table", destroy_resolver_idtabcb +}; + /*---------- query, query option and answers - common stuff ----------*/ #define RRTYPE_EXACTLY(t) { #t, adns_r_##t } @@ -316,7 +338,7 @@ static const OptionInfo query_optioninfos[]= { static int query_submit(Tcl_Interp *ip, const AdnsTclRRTypeInfo *type, const char *domain, int queryopts_objc, Tcl_Obj *const *queryopts_objv, - adns_query *aqu_r, OptionParse *op) { + adns_query *aqu_r, void *context, OptionParse *op) { struct sockaddr sa; static const int aftry[]= { AF_INET, AF_INET6 }; int rc, r, ec; @@ -324,7 +346,8 @@ static int query_submit(Tcl_Interp *ip, op->aflags= adns_qf_owner; op->sflags= 0; - op->resolver= 0; + op->resolver= 0; /* fixme default */ + op->reverseany= 0; rc= parse_options(ip, queryopts_objc,queryopts_objv, query_optioninfos,op); if (rc) return rc; @@ -344,13 +367,13 @@ static int query_submit(Tcl_Interp *ip, if (op->reverseany) { ec= adns_submit_reverse_any(ads, &sa, op->reverseany, - type->number, op->aflags, 0, aqu_r); + type->number, op->aflags, context, aqu_r); } else if (op->sflags & oisf_reverse) { ec= adns_submit_reverse(ads, &sa, - type->number, op->aflags, 0, aqu_r); + type->number, op->aflags, context, aqu_r); } else { ec= adns_submit(ads, domain, - type->number, op->aflags, 0, aqu_r); + type->number, op->aflags, context, aqu_r); } if (ec) return posixerr(ip,ec,"submit adns query"); @@ -370,7 +393,7 @@ static void make_resultstatus(Tcl_Interp *ip, adns_status status, } static Tcl_Obj *make_resultrdata(Tcl_Interp *ip, adns_answer *answer) { - Tcl_Obj **rdata; + Tcl_Obj **rdata, *rl; int i, rrsz; adns_status st; char *datap, *rdatastring; @@ -384,8 +407,9 @@ static Tcl_Obj *make_resultrdata(Tcl_Interp *ip, adns_answer *answer) { rdata[i]= ret_string(ip, rdatastring); free(rdatastring); } + rl= Tcl_NewListObj(answer->nrrs, rdata); TFREE(rdata); - return Tcl_NewListObj(answer->nrrs, rdata); + return rl; } static void make_resultlist(Tcl_Interp *ip, adns_answer *answer, @@ -408,7 +432,7 @@ static int synch(Tcl_Interp *ip, const AdnsTclRRTypeInfo *rrtype, Resolver *res; int rc, ec; - rc= query_submit(ip,rrtype,domain,objc,objv,&aqu,&op); + rc= query_submit(ip,rrtype,domain,objc,objv,&aqu,0,&op); if (rc) return rc; res= op.resolver; @@ -458,15 +482,13 @@ int do_adns_synch(ClientData cd, Tcl_Interp *ip, /*---------- asynchronous query handling ----------*/ -typedef struct { +struct Query { int ix; /* first! */ Resolver *res; adns_query aqu; ScriptToInvoke on_yes, on_no, on_fail; Tcl_Obj *xargs; -} Query; - -IdDataTable adnstcl_queries= { "adns" }; +}; static void asynch_timerhandler(void *res_v) { Resolver *res= res_v; @@ -526,16 +548,6 @@ static void asynch_sethandlers(Resolver *res, int shutdown) { } } -static void asynch_query_dispose(Query *query) { - tabledataid_disposing(query, &adnstcl_queries); - scriptinv_cancel(&query->on_yes); - scriptinv_cancel(&query->on_no); - scriptinv_cancel(&query->on_fail); - if (query->xargs) Tcl_DecrRefCount(query->xargs); - if (query->aqu) adns_cancel(query->aqu); - TFREE(query); -} - static void asynch_check(Resolver *res) { Tcl_Interp *interp= res->interp; adns_query aqu; @@ -553,7 +565,7 @@ static void asynch_check(Resolver *res) { query= query_v; query->aqu= 0; - tabledataid_disposing(query, &adnstcl_queries); + tabledataid_disposing(interp, query, &adnstcl_queries); si= (!answer->status ? si= &query->on_yes : answer->status > adns_s_max_tempfail ? &query->on_no @@ -562,7 +574,7 @@ static void asynch_check(Resolver *res) { make_resultlist(interp, answer, results); free(answer); scriptinv_invoke(si, RESULTLIST_LLEN, results); - asynch_query_dispose(query); + asynch_query_dispose(interp, query); } asynch_sethandlers(res,0); @@ -586,7 +598,7 @@ int do_adns_asynch(ClientData cd, Tcl_Interp *ip, scriptinv_init(&query->on_fail); query->xargs= 0; - rc= query_submit(ip,rrtype,domain,objc,objv,&query->aqu,&op); + rc= query_submit(ip,rrtype,domain,objc,objv,&query->aqu,query,&op); if (rc) goto x_rc; res= op.resolver; @@ -601,7 +613,7 @@ int do_adns_asynch(ClientData cd, Tcl_Interp *ip, return TCL_OK; x_rc: - if (query) asynch_query_dispose(query); + if (query) asynch_query_dispose(ip, query); if (res) asynch_sethandlers(res,0); return rc; } @@ -609,8 +621,25 @@ int do_adns_asynch(ClientData cd, Tcl_Interp *ip, int do_adns_asynch_cancel(ClientData cd, Tcl_Interp *ip, void *query_v) { Query *query= query_v; Resolver *res= query->res; - - asynch_query_dispose(query); + asynch_query_dispose(ip, query); asynch_sethandlers(res,0); return TCL_OK; } + +static void asynch_query_dispose(Tcl_Interp *interp, Query *query) { + tabledataid_disposing(interp, query, &adnstcl_queries); + scriptinv_cancel(&query->on_yes); + scriptinv_cancel(&query->on_no); + scriptinv_cancel(&query->on_fail); + if (query->xargs) Tcl_DecrRefCount(query->xargs); + if (query->aqu) adns_cancel(query->aqu); + TFREE(query); +} + +static void destroy_query_idtabcb(Tcl_Interp *interp, void *query_v) { + asynch_query_dispose(interp, query_v); +} + +const IdDataSpec adnstcl_queries= { + "adns", "adns-query-table", destroy_query_idtabcb +}; diff --git a/base/chiark-tcl.h b/base/chiark-tcl.h index 2b03287..b49301f 100644 --- a/base/chiark-tcl.h +++ b/base/chiark-tcl.h @@ -215,10 +215,9 @@ void scriptinv_invoke(ScriptToInvoke *si, int argc, Tcl_Obj **argv); /* from idtable.c */ typedef struct { - const char *const prefix; - int n; - void **a; -} IdDataTable; + const char *valprefix, *assockey; + void (*destroyitem)(Tcl_Interp *ip, void *val); +} IdDataSpec; /* The stored struct must start with a single int, conventionally * named `ix'. When the struct is returned for the first time ix must @@ -226,10 +225,10 @@ typedef struct { * the struct is registered by the iddatatable machinery. */ extern Tcl_ObjType tabledataid_nearlytype; -int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, IdDataTable *tab); -void tabledataid_disposing(void *val, IdDataTable *tab); +int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, const IdDataSpec *idds); +void tabledataid_disposing(Tcl_Interp *ip, void *val, const IdDataSpec *idds); /* call this when you destroy the struct, to remove its name; - * _disposing is idempotent*/ + * _disposing is idempotent */ /* from adns.c */ @@ -238,16 +237,16 @@ typedef struct { adns_rrtype number; } AdnsTclRRTypeInfo; -extern IdDataTable adnstcl_queries, adnstcl_resolvers; +extern const IdDataSpec adnstcl_queries, adnstcl_resolvers; /* from dgram.c */ -extern IdDataTable dgram_socks; +extern const IdDataSpec dgram_socks; int newfdposixerr(Tcl_Interp *ip, int fd, const char *m); /* from tuntap.c */ -extern IdDataTable tuntap_socks; +extern const IdDataSpec tuntap_socks; /* from hook.c */ diff --git a/base/idtable.c b/base/idtable.c index f64a101..b23a97c 100644 --- a/base/idtable.c +++ b/base/idtable.c @@ -6,56 +6,104 @@ /* Arg parsing */ -static void setobjdataid(Tcl_Obj *o, int ix, IdDataTable *tab) { - unsigned long *ulp; +typedef struct { + const IdDataSpec *idds; + int n; + void **a; +} IdDataAssocData; + +typedef struct { + Tcl_Interp *interp; + IdDataAssocData *assoc; + int ix; +} IdDataValue; + +static void assoc_del(ClientData assoc_cd, Tcl_Interp *ip) { + IdDataAssocData *assoc; + int ix; + void **p, *v; + + assoc= assoc_cd; + for (ix=0, p=assoc->a; ixn; ix++, p++) { + v= *p; + if (!v) continue; + assert(*(int*)v == ix); + *(int*)v= -1; + assoc->idds->destroyitem(ip,v); + *p= 0; + } + TFREE(assoc->a); + TFREE(assoc); +} + +static void setobjdataid(Tcl_Interp *interp, Tcl_Obj *o, + int ix, const IdDataSpec *idds) { + IdDataValue *dv; + IdDataAssocData *assoc; + + assoc= Tcl_GetAssocData(interp, (char*)idds->assockey, 0); + if (!assoc) { + assoc= TALLOC(sizeof(*assoc)); + assoc->idds= idds; + assoc->n= 0; + assoc->a= 0; + Tcl_SetAssocData(interp, (char*)idds->assockey, assoc_del, assoc); + } + + dv= TALLOC(sizeof(*dv)); + dv->interp= interp; + dv->assoc= assoc; + dv->ix= ix; - ulp= TALLOC(sizeof(unsigned long)); - *ulp= ix; - o->internalRep.twoPtrValue.ptr1= tab; - o->internalRep.twoPtrValue.ptr2= ulp; o->typePtr= &tabledataid_nearlytype; + o->internalRep.otherValuePtr= dv; } -int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, IdDataTable *tab) { +int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, const IdDataSpec *idds) { int l; unsigned long ul; + IdDataValue *dv; + IdDataAssocData *assoc; char *ep, *str; - if (o->typePtr == &tabledataid_nearlytype && - o->internalRep.twoPtrValue.ptr1 == tab) return TCL_OK; + if (o->typePtr != &tabledataid_nearlytype) goto convert; + + dv= o->internalRep.otherValuePtr; + if (dv->interp != ip) goto convert; + assoc= dv->assoc; + if (dv->assoc->idds != idds) goto convert; - l= strlen(tab->prefix); + return TCL_OK; + +convert: + l= strlen(idds->valprefix); str= Tcl_GetStringFromObj(o,0); - if (memcmp(str,tab->prefix,l)) + if (memcmp(str,idds->valprefix,l)) return staticerr(ip,"bad id (wrong prefix)",0); + errno=0; ul=strtoul(str+l,&ep,10); if (errno || *ep) return staticerr(ip,"bad id number",0); if (ul > INT_MAX) return staticerr(ip,"out of range id number",0); objfreeir(o); - setobjdataid(o,ul,tab); + setobjdataid(ip,o,ul,idds); return TCL_OK; } -void tabledataid_disposing(void *val, IdDataTable *tab) { - int ix; - - ix= *(int*)val; - if (ix==-1) return; - assert(tab->a[ix] == val); - tab->a[ix]= 0; - *(int*)val= -1; -} - -int pat_iddata(Tcl_Interp *ip, Tcl_Obj *o, void **rv, IdDataTable *tab) { +int pat_iddata(Tcl_Interp *ip, Tcl_Obj *o, void **rv, const IdDataSpec *idds) { int rc, ix; + IdDataValue *dv; + IdDataAssocData *assoc; void *r; - rc= tabledataid_parse(ip,o,tab); + rc= tabledataid_parse(ip,o,idds); if (rc) return rc; - ix= *(unsigned long*)o->internalRep.twoPtrValue.ptr2; - if (ix >= tab->n || !(r= tab->a[ix])) + dv= o->internalRep.otherValuePtr; + ix= dv->ix; + assoc= dv->assoc; + + if (ix >= assoc->n || !(r= assoc->a[ix])) return staticerr(ip,"id not in use",0); assert(*(int*)r == ix); @@ -64,59 +112,86 @@ int pat_iddata(Tcl_Interp *ip, Tcl_Obj *o, void **rv, IdDataTable *tab) { return TCL_OK; } -Tcl_Obj *ret_iddata(Tcl_Interp *ip, void *val, IdDataTable *tab) { +Tcl_Obj *ret_iddata(Tcl_Interp *ip, void *val, const IdDataSpec *idds) { /* Command procedure implementation may set val->ix, * ie *(int*)val, to -1, to mean it's a new struct. Otherwise * it had better be an old one ! */ Tcl_Obj *o; + IdDataValue *dv; + IdDataAssocData *assoc; int ix; + o= Tcl_NewObj(); + setobjdataid(ip,o,0,idds); + dv= o->internalRep.otherValuePtr; + assoc= dv->assoc; + ix= *(int*)val; if (ix==-1) { - for (ix=0; ixn && tab->a[ix]; ix++); - if (ix>=tab->n) { - tab->n += 2; - tab->n *= 2; - tab->a= (void*)Tcl_Realloc((void*)tab->a, tab->n*sizeof(*tab->a)); - while (ixn) tab->a[ix++]=0; + for (ix=0; ixn && assoc->a[ix]; ix++); + if (ix>=assoc->n) { + assoc->n += 2; + assoc->n *= 2; + assoc->a= TREALLOC(assoc->a, assoc->n*sizeof(*assoc->a)); + while (ixn) assoc->a[ix++]=0; ix--; } - tab->a[ix]= val; + assoc->a[ix]= val; *(int*)val= ix; } else { - assert(val == tab->a[ix]); + assert(val == assoc->a[ix]); } - - o= Tcl_NewObj(); - setobjdataid(o,ix,tab); + dv->ix= ix; Tcl_InvalidateStringRep(o); return o; } +void tabledataid_disposing(Tcl_Interp *ip, void *val, const IdDataSpec *idds) { + IdDataAssocData *assoc; + int ix; + + ix= *(int*)val; + if (ix==-1) return; + + assoc= Tcl_GetAssocData(ip, (char*)idds->assockey, 0); + assert(assoc->a[ix] == val); + assoc->a[ix]= 0; + *(int*)val= -1; +} + static int tabledataid_nt_sfa(Tcl_Interp *ip, Tcl_Obj *o) { abort(); } static void tabledataid_nt_free(Tcl_Obj *o) { - TFREE(o->internalRep.twoPtrValue.ptr2); - o->internalRep.twoPtrValue.ptr2= 0; + TFREE(o->internalRep.otherValuePtr); + o->internalRep.otherValuePtr= 0; } static void tabledataid_nt_dup(Tcl_Obj *src, Tcl_Obj *dup) { - setobjdataid(dup,*(unsigned long*)src->internalRep.twoPtrValue.ptr2, - src->internalRep.twoPtrValue.ptr1); + IdDataValue *sv, *dv; + + sv= src->internalRep.otherValuePtr; + dv= TALLOC(sizeof(*dv)); + *dv= *sv; + dup->typePtr= &tabledataid_nearlytype; + dup->internalRep.otherValuePtr= dv; } static void tabledataid_nt_ustr(Tcl_Obj *o) { + const IdDataValue *dv; + const IdDataAssocData *assoc; + const IdDataSpec *idds; char buf[75]; - const char *prefix; - prefix= ((IdDataTable*)o->internalRep.twoPtrValue.ptr1)->prefix; - snprintf(buf,sizeof(buf), "%lu", - *(unsigned long*)o->internalRep.twoPtrValue.ptr2); + dv= o->internalRep.otherValuePtr; + assoc= dv->assoc; + idds= assoc->idds; + + snprintf(buf,sizeof(buf), "%d", dv->ix); obj_updatestr_vstringls(o, - prefix, strlen(prefix), + idds->valprefix, strlen(idds->valprefix), buf, strlen(buf), (char*)0); } diff --git a/base/tables-examples.tct b/base/tables-examples.tct index 696583a..98c6cd9 100644 --- a/base/tables-examples.tct +++ b/base/tables-examples.tct @@ -14,7 +14,7 @@ Fini maskmapv fini_somethingv(ip, rc, &@.sth); Type sockaddr: SockAddr_Value @ Init sockaddr sockaddr_clear(&@); -Type iddata(IdDataTable *tab): void *@ +Type iddata(const IdDataSpec *idds): void *@ Type ulong: uint32_t @ Type long: long @ Type string: const char *@ diff --git a/dgram/dgram.c b/dgram/dgram.c index 08f5f45..ff16917 100644 --- a/dgram/dgram.c +++ b/dgram/dgram.c @@ -21,8 +21,6 @@ typedef struct DgramSocket { int addr_buflen, msg_buflen; } DgramSocket; -IdDataTable dgram_socks= { "dgramsock" }; - int do_dgram_socket_create(ClientData cd, Tcl_Interp *ip, SockAddr_Value local, void **sock_r) { int fd, al, r; @@ -152,14 +150,24 @@ int do_dgram_socket_on_receive(ClientData cd, Tcl_Interp *ip, return TCL_OK; } -int do_dgram_socket_close(ClientData cd, Tcl_Interp *ip, void *sock_v) { - DgramSocket *sock= sock_v; - +static void destroy(DgramSocket *sock) { cancel(sock); close(sock->fd); /* nothing useful to be done with errors */ - tabledataid_disposing(sock,&dgram_socks); TFREE(sock->addr_buf); TFREE(sock->msg_buf); TFREE(sock); +} + +static void destroy_idtabcb(Tcl_Interp *ip, void *sock_v) { + destroy(sock_v); +} + +int do_dgram_socket_close(ClientData cd, Tcl_Interp *ip, void *sock_v) { + destroy(sock_v); + tabledataid_disposing(ip,sock_v,&dgram_socks); return TCL_OK; } + +const IdDataSpec dgram_socks= { + "dgramsock", "dgramsock-table", destroy_idtabcb +}; diff --git a/hbytes/hbytes.h b/hbytes/hbytes.h index 2b03287..b49301f 100644 --- a/hbytes/hbytes.h +++ b/hbytes/hbytes.h @@ -215,10 +215,9 @@ void scriptinv_invoke(ScriptToInvoke *si, int argc, Tcl_Obj **argv); /* from idtable.c */ typedef struct { - const char *const prefix; - int n; - void **a; -} IdDataTable; + const char *valprefix, *assockey; + void (*destroyitem)(Tcl_Interp *ip, void *val); +} IdDataSpec; /* The stored struct must start with a single int, conventionally * named `ix'. When the struct is returned for the first time ix must @@ -226,10 +225,10 @@ typedef struct { * the struct is registered by the iddatatable machinery. */ extern Tcl_ObjType tabledataid_nearlytype; -int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, IdDataTable *tab); -void tabledataid_disposing(void *val, IdDataTable *tab); +int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, const IdDataSpec *idds); +void tabledataid_disposing(Tcl_Interp *ip, void *val, const IdDataSpec *idds); /* call this when you destroy the struct, to remove its name; - * _disposing is idempotent*/ + * _disposing is idempotent */ /* from adns.c */ @@ -238,16 +237,16 @@ typedef struct { adns_rrtype number; } AdnsTclRRTypeInfo; -extern IdDataTable adnstcl_queries, adnstcl_resolvers; +extern const IdDataSpec adnstcl_queries, adnstcl_resolvers; /* from dgram.c */ -extern IdDataTable dgram_socks; +extern const IdDataSpec dgram_socks; int newfdposixerr(Tcl_Interp *ip, int fd, const char *m); /* from tuntap.c */ -extern IdDataTable tuntap_socks; +extern const IdDataSpec tuntap_socks; /* from hook.c */ diff --git a/tuntap/tuntap.c b/tuntap/tuntap.c index 7a1d268..f45b3c9 100644 --- a/tuntap/tuntap.c +++ b/tuntap/tuntap.c @@ -26,8 +26,6 @@ typedef struct TunSocket { char *ifname; } TuntapSocket; -IdDataTable tuntap_socks= { "tuntap" }; - int do_tuntap_socket_raw_create(ClientData cd, Tcl_Interp *ip, const char *ifname, void **sock_r) { int fd, r; @@ -142,15 +140,24 @@ int do_tuntap_socket_raw_on_transmit(ClientData cd, Tcl_Interp *ip, return TCL_OK; } -int do_tuntap_socket_raw_close(ClientData cd, Tcl_Interp *ip, void *sock_v) { +static void destroy(void *sock_v) { TuntapSocket *sock= sock_v; - - int sockix; cancel(sock); close(sock->fd); /* nothing useful to be done with errors */ - sockix= sock->ix; TFREE(sock->msg_buf); TFREE(sock); - tuntap_socks.a[sockix]= 0; +} + +static void destroy_idtabcb(Tcl_Interp *ip, void *sock_v) { + destroy(sock_v); +} + +int do_tuntap_socket_raw_close(ClientData cd, Tcl_Interp *ip, void *sock) { + destroy(sock); + tabledataid_disposing(ip,sock,&tuntap_socks); return TCL_OK; } + +const IdDataSpec tuntap_socks= { + "tuntap", "tuntap-table", destroy_idtabcb +};