chiark / gitweb /
avoid invoking callback procedures other than from event handlers, by using a zero...
[chiark-tcl.git] / adns / adns.c
index 585ce399b1fa890b3f63056876b2b2c266d8dfe2..d8b6e1c35de122693cb7352820d8a0bd56b0186a 100644 (file)
 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_sethandlers(Resolver *res);
+static void asynch_cancelhandlers(Resolver *res);
+static void asynch_perturbed(Resolver *res);
+
 static void asynch_query_dispose(Tcl_Interp *interp, Query *query);
 
 /*---------- common resolver/query option processing ----------*/
@@ -217,7 +220,7 @@ static void destroy_resolver(Tcl_Interp *ip, Resolver *res) {
     }
     adns_finish(res->ads);
   }
-  asynch_sethandlers(res,1);
+  asynch_cancelhandlers(res);
   TFREE(res);
   /* fixme what about the default resolver */
 }
@@ -439,7 +442,7 @@ static int synch(Tcl_Interp *ip, const AdnsTclRRTypeInfo *rrtype,
   ec= adns_wait(res->ads,&aqu,answer_r,0);
   assert(!ec);
 
-  asynch_check(res);
+  asynch_perturbed(res);
   return TCL_OK;
 }
 
@@ -490,11 +493,13 @@ struct Query {
   Tcl_Obj *xargs;
 };
 
+static void asynch_check_now(Resolver *res);
+
 static void asynch_timerhandler(void *res_v) {
   Resolver *res= res_v;
   res->timertoken= 0;
   adns_processtimeouts(res->ads,0);
-  asynch_check(res);
+  asynch_check_now(res);
 }
 
 static void asynch_filehandler(void *res_v, int mask) {
@@ -503,10 +508,12 @@ static void asynch_filehandler(void *res_v, int mask) {
   
   ec= adns_processany(res->ads);
   if (ec) adns_globalsystemfailure(res->ads);
-  asynch_check(res);
+  asynch_check_now(res);
 }
 
-static void asynch_sethandlers(Resolver *res, int shutdown) {
+static void asynch_sethandlers_generic(Resolver *res,
+                                      int shutdown /*from _cancelhandlers*/,
+                                      int immediate /*from _perturbed*/) {
   fd_set want[3];
   int maxfd;
   struct timeval tv_buf, *timeout;
@@ -534,7 +541,9 @@ static void asynch_sethandlers(Resolver *res, int shutdown) {
 
   Tcl_DeleteTimerHandler(res->timertoken);
 
-  if (timeout) {
+  if (immediate) {
+    res->timertoken= Tcl_CreateTimerHandler(0,asynch_timerhandler,res);
+  } else if (timeout) {
     int milliseconds;
 
     if (timeout->tv_sec >= INT_MAX/1000 - 1)
@@ -548,7 +557,17 @@ static void asynch_sethandlers(Resolver *res, int shutdown) {
   }
 }
 
-static void asynch_check(Resolver *res) {
+static void asynch_sethandlers(Resolver *res) {
+  asynch_sethandlers_generic(res,0,0);
+}
+static void asynch_cancelhandlers(Resolver *res) {
+  asynch_sethandlers_generic(res,1,0);
+}
+static void asynch_perturbed(Resolver *res) {
+  asynch_sethandlers_generic(res,0,1);
+}
+
+static void asynch_check_now(Resolver *res) {
   Tcl_Interp *interp= res->interp;
   adns_query aqu;
   adns_answer *answer;
@@ -578,7 +597,7 @@ static void asynch_check(Resolver *res) {
     asynch_query_dispose(interp, query);
   }
 
-  asynch_sethandlers(res,0);
+  asynch_sethandlers(res);
 }
     
 int do_adns_asynch(ClientData cd, Tcl_Interp *ip,
@@ -615,7 +634,7 @@ int do_adns_asynch(ClientData cd, Tcl_Interp *ip,
 
  x_rc:
   if (query) asynch_query_dispose(ip, query);
-  if (res) asynch_sethandlers(res,0);
+  if (res) asynch_perturbed(res);
   return rc;
 }
 
@@ -623,7 +642,7 @@ int do_adns_asynch_cancel(ClientData cd, Tcl_Interp *ip, void *query_v) {
   Query *query= query_v;
   Resolver *res= query->res;
   asynch_query_dispose(ip, query);
-  asynch_sethandlers(res,0);
+  asynch_perturbed(res);
   return TCL_OK;
 }