ossp-pkg/sio/al_todo.txt
o rse: memory chunk maintainance
A piece of memory usually has the following 4 attributes which fully
describe it:
memory location: <pointer,length,size,refcount>
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.