Sorry, these code is NOT written by me, it's by Erik Huelsmann. I just confirmed them when I was adding UDP support to WAIT-FOR-INPUT-INTERNAL.
--binghe > Hi, Anton > > Thank you very much for your patient explanation, now I completely understand > this:) > > The USOCKET SBCL/win32 supporting code is port from LispWorks/win32 > supporting code, this is how LispWorks do the same work: > > (defun free-wait-list (wl) > (when (wait-list-p wl) > (unless (null (wait-list-%wait wl)) > (wsa-event-close (wait-list-%wait wl))))) > > (eval-when (:load-toplevel :execute) > (hcl:add-special-free-action 'free-wait-list)) > > (defun %setup-wait-list (wait-list) > (hcl:flag-special-free-action wait-list) > (setf (wait-list-%wait wait-list) (wsa-event-create))) > > I confirmed above code could really work when I first wrote them. As you can > see, LW allow me using HCL:ADD-SPECIAL-FREE-ACTION to register a general > handler function for cleaning every needed object. The handler function > FREE-WAIT-LIST have to check its argument type first, and then do its > cleaning job, because other type of object could come in. And in > %SETUP-WAIT-LIST, I need to call HCL:FLAG-SPECIAL-FREE-ACTION to mark the > wait-list object to be "cleanable". No closure needed here, but seems if I > have many different action functions, things could do a bit slower than the > SBCL way. > > Any way, just want to share this. No other issue. > > Regards, > > Chun Tian (binghe) > > 在 2011-3-22,14:38, Anton Kovalenko 写道: > >> "Chun Tian (binghe)" <binghe.l...@gmail.com> writes: >> >>> I think I cannot understand why the closure must close over those >>> components of WAIT-LIST but WAIT-LIST itself, but since this is a fact >>> (as you confirmed), I'd like to adopt your patches and quote all your >>> explanations and put with the new code together. I hope, with your >>> SBCL and USOCKET work, Hunchentoot (and other Lisp-based servers) >>> could have a beautiful future on Windows platform. >> >> Thank you! >> >> The problem with a closure and a finalizer is not too complicated (i'm >> now trying to rephrase my explanations to be easy to understand): >> >> A queue of finalizers (sb-impl::**finalizer-store** in SBCL, but other >> CL implementanions usually have some equivalent) is just a mundane >> special variable (containing a list in SBCL case). Special variable >> values (if we forget thread-local bindings and uninterned symbols) are >> always reachable in Common Lisp: it's easy, for example, to write a loop >> that iterates over packages and symbols and examines each SYMBOL-VALUE. >> >> GC _doesn't collect reachable objects_. If there is a closure with an >> object `inside', it's considered reachable too. And if an object isn't >> collected, it's not the time (from GC's point of view) to run its >> finalizers, so they are not run. >> >> >> Anyone who wants to build a GC with other behavior will be confronted by >> a very complicated picture: instead of two kinds of objects ("reachable" >> and "unreachable" (from some roots)) we must consider _which code_ can >> reach the object and which code cannot. If we introduce a single >> "magical" exception into the simple dichotomy of live and dead object >> (like finalizer queue -- if it were a "zombie place" of this kind), >> complicated GC implementation will be only a half of our problems; >> questions like "what if one finalizer refers to the object of another >> one?" will soon make us confused -- not only about how to implement the >> GC, but about _what_ we should implement. >> >> SBCL is not alone in taking the simple way; and, when we decide that >> finalizers (that are notified about dead objects) shouldn't see those >> objects, a beautiful thing happens: _weak pointers and finalizers_ >> become logically equivalent and mutually interchangeable. >> >> In particular, SBCL's finalizer queue is just an alist of weak pointers >> to objects in CAR and closures in CDR. After each "low-level" GC >> invokation, SBCL looks for those weak pointers in **finalizer-store** >> that became dead, and invokes the closures. >> >> [Just as a curiosity, it's possible to go in the opposite direction: to >> implement weak pointers when the finalizers are "given". Never seen it >> in real life, however: weak pointer support is likely a natural >> byproduct of low-level GC work, and finalizer support likely isn't]. >> >> If not weak pointers, weak hash tables provide the base for finalizer >> support in the same way. [Having weak hash table support _inside_ is >> almost a must for any Common Lisp implementation -- or else each >> interned and uninterned symbol increases memory consumption >> irreversibly]. >> >> Almost any programmer now has some experience with C++ destructors, so >> it's especially important not to misapply that experience to >> finalizers. The common trait of finalizers that is described above is >> _opposed_ to the very definition and purpose of destructors. >> >> Destructors are like some evil creditor, speaking continuously "I hope >> you won't die in debt". Finalizers are like some relative notifying you >> of the burial of other relative. Unsure which picture is more sad, but >> the latter is more natural and less evil. >> >> -- >> Regards, Anton Kovalenko >> +7(916)345-34-02 | Elektrostal' MO, Russia > _______________________________________________ usocket-devel mailing list usocket-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/usocket-devel