o rse: memory chunk maintainance A piece of memory usually has the following 4 attributes which fully describe it: memory location: memory type: STACK|HEAP|SHMEM|CUSTOM memory scope: LOAN|GIFT|[COPY] memory access: READ_ONLY|READ_WRITE With the current al_chunk_t/al_buffer_t such a description is only partly possible, although IMHO (after efficiency) this flexibility in describing arbitrary memory chunks has to be #1 priority. Currently only al_attach_buffer() allows insertion of externally provided memory chunks. But these then have to be malloc(3)'ed and are not allowed to be allocated differently. For this the CUSTOM type would allow arbitrary memory chunks to be specified for an application provided destruction callback exists. x mlelstv: insertion of externally provided memory chunks is the exception, not the rule. Previously it couldn't be malloc'ed because it was almost impossible to free it later. The latest change to the API provides the necessary destruction callback. I don't see specific "memory types" yet. Currently memory can be allocated and freed. If we support "memory types" we need a specific "memory" library that abstracts from these types beyond malloc() and free(). Things like cache-coherency or atomic access come to my mind. Memory scopes are implied by the specific operations: user API: LOAN == al_attach_buffer (and COPY with al_*_bytes) internally: GIFT == al_splice (and COPY) Providing public GIFT semantic requires to expose the internal memory allocator. That's why I use LOAN. No ideas about "memory access" types yet. What is the use for a "read-only" assembly line ? o rse: al.pod, DESCRIPTION: perhaps add the buzzwords "zero-copy" and "efficient" somewhere just to make sure people recognize that OSSP al is not "just another trivial buffer library" ;) x mlelstv: it is "copy avoidance" but not "zero-copy". o rse: al.pod, al_attach_buffer: scope still does not say anything about the content, i.e., is it allowed that the application still changes the content (as long as the size does not change)? x mlelstv: the buffer is loaned to the library. Previously you wouldn't know when it is returnd (and thus available). Now a callback function is used to hand the buffer back. The same mechanism is used internally for buffers allocated by the library. o rse: recommended renamings: public: al_txalloc -> al_tx_create al_txfree -> al_tx_destroy al_traverse -> al_traverse_start al_traverse_cb -> al_apply private: new_buffer -> buffer_new dispose_buffer -> buffer_dispose make_buffer -> buffer_make new_chunk -> chunk_new split_chunk -> chunk_split dispose_chunk -> chunk_dispose x mlelstv: alloc/free vs create/destroy: al_tx_t is no object, thus no constructor, just an allocator. And that's denoted in the function name. al_apply sounds neat, but then al_traverse* need some neat names too. private naming: I don't like the change. Current names are english phrases. "new" (== verb) "buffer" (== subject). o thl: sanity checks and return of AL_ERR_ARG x mlelstv: ACK o thl: Es fehlt eine al_configure() call mit dem man die al_memops_t beeinflussen kann. x mlelstv: memops sind bisher private, sind sie ausreichend fuer public API ? Ich glaube nicht. Und "erweiterbare" APIs wuerde ich gerne vermeiden. o thl: Beim splicen entstehen shared buffers und deren bisherige Behandlung ist rudimentaer, sorgt aber bereits fuer merklich Overhead usecount in al_buffer_t). Das transferieren von Teilen solcher shared buffer von einer al in eine andere ist derzeit ein Limit der Library. Ein versehentliches anhaengen von Daten in anscheinend freie Bufferbereiche, die aber doch von anderen Chunks genutzt werden, wird derzeit schlicht durch Totalverweigerung der Nutzung von evtl. freien Bufferbereichen bei shared buffers verhindert, indem AL_CHUNK_RESERVE() einfach immer "null Platz" fuer shared buffer (usecount > 1) zurueckgibt. Aehnliches gilt fuer das gift/loan Verhalten, wegen al_attach_buffer() muss extra ein freemem flag mitgescheift werden. Aber es wird gemacht und funktioniert und ich wuesste auch keinen besseren Weg. x mlelstv: usecount is notwendig, wenn man zukuenftig aliasing (== copy-on-write) unterstuetzen will. Eine feinere Behandlung von shared buffers wuerde ich, gerade wegen des Overheads, vermeiden wollen. Buffer-Sharing dient nicht dem Sparen von Speicher sondern dem Verhindern von Kopieroperationen. freemem ist nicht laenger ein Flag, sondern ein (optionaler) Callback. Flexibler. o thl: Es ist weder in der Doku noch im Code beruecksichtigt, dass die Assembly List zwischen al_traverse() und al_txfree() nicht veraendert werden darf. Ist auch nicht ganz so einfach zu erklaeren, denn veraendern heisst z.B. splicen. Appenden und prependen stoert wohl nicht. Es gehen aber die waehrend des traversals dazugekommenen Daten dem al_traverse_next() durch die Lappen, da die Datenmenge beim al_traverse() berechnet wird. x mlelstv: Korrekt. Erster Ansatz ist ein al_traverse_end() mit dem man ein Traversal abschliesst (oder temporaer abschliesst, damit die notwendige Re-Initialisierung automatisch wieder vorgenommen werden kann). o rse: the library is not threadsafe nor even reentrant because there are two static variables: alc_freelist, alc_freecount. x mlelstv: ACK solution 1: keep per al_t freelists, simple, but doesn't allow a shared freelist. solution 2: add global context that can be hooked into thread libraries. solution 3: defer problem to a grid allocator library I suggest solution 3 :) o rse: the list.h macros lack a common prefix. x mlelstv: wenn schon dann XML namespaces.... >-) o rse: al_rc_t al_txalloc (al_t *al, al_tx_t **tx); al_rc_t al_txfree (al_t *al, al_tx_t *tx); -al_rc_t al_traverse (al_t *al, size_t off, size_t n, al_td_t dir, al_tx_t *tx); +al_rc_t al_traverse (al_t *al, al_tx_t *tx, size_t off, size_t n, al_td_t dir); al_rc_t al_traverse_next(al_t *al, al_tx_t *tx, al_chunk_t **alcp); al_rc_t al_traverse_end (al_t *al, al_tx_t *tx, int final); mlelstv: parameter order is: object ptr(if any), input parameters, output parameters rse: Nun, generell ist deine "obj-ptr, input[, ...], output[, ...]" Reihenfolge voellig ok. Der Punkt ist nur, dasz es eigentlich "obj-ptr[, ...], input, [,...], output, [,...]" ist, sprich es kann durchaus bei Sub-APIs mehrere Object Pointer geben. Und genau das ist bei dir ja der Fall IMHO. Denn das al_tx_t und die Functions al_txalloc, al_txfree, al_traverse, al_traverse_next und al_traverse_end bilden bei dir ja eine solche Sub-API. Und deswegen wuerde ich das al_tx_t auch als zweites Argument bei al_traverse sehen. Denn obendrein: wenn es man es genau nimmt, ist das al_tx_t ja nicht nur bei al_traverse ein Output Parameter, denn die anderen Funktionen aendern ihn ja auch ab. Wenn man also streng zwischen Input und Output-Parameters unterscheidet, dann duerften Input Parameter also nie veraendert werden (wenn sie nicht eh per Kopie reingehen). Die Input/Output-Regel ist also streng genommen bereits durch al_traverse_next gebrochen IMHO.