On Mon, Aug 1, 2016 at 12:50 AM, Gustavo Sverzut Barbieri <barbi...@gmail.com> wrote: [...] > /* see http://solettaproject.github.io/docs/c-api/structsol__blob.html [...] > struct Eina.Blob { > mem: void_ptr; > parent: Eina.Blob; > size: size; > refcount: int; > free: Eina_Blob_Free_Cb; > }
To address some comments from IRC, that's not the real structure we should go with, maybe it would be @extern, maybe opaque with native symbols to create these things all defined in C (such as mmap for file readers, others that adopt a malloc, others that adopt a static-const and last but not least others that do create "child" or "windows"). Think of this as read-only memory that have references to the parent and allows slice or windows. And the memory doesn't need to be allocated with malloc, such as: - protocols that use fixed strings can avoid strdup() by using static-const stuff. No free() is needed; - files can be read using mmap, free() is actually munmap() - slices of another memory, like a line in an mmap file, no free() to be called on that memory. But once the slice itself is unloaded, the mmap must go away if that's the last reference. Also, this is optional, but in my other project, Soletta, we found it saves some memory and could be of use in EFL. We could keep the pattern currently used that uses a binbuf to copy the given data. [reordered the email contents to have send() closer] > methods { > send @virtual_pure { > [[Queue data to be sent to remote]] > params { > @in data: Eina.Blob; [[data to queue for sending]] ... > events { > sent: Eina.Blob, error; [[data specified by blob was sent, > if error != 0, contains errno]] pseudo code is like: send(Eina.Blob data) { queue.append(ref(data)); fd.active_set(fd.active_get() | ECORE_FD_WRITE); } _on_can_write() { first_blob = queue[0] /* this can be more optimized by usage of iovec variant with multiple blobs being sent */ n = write(fd, first_blob.mem + write_offset, first_blob.size - write_offset); if (n < 0) { notify error; return; } write_offset += n; if (write_offset < first_blob.size) return; emit("sent", first_blob, 0); // no error write_offset = 0; queue.pop(); if (queue.len > 0) return; fd.active_set(fd.active_get() & (~ECORE_FD_WRITE)); } > events { > read @hot: Eina.Binbuf; [[data is available to read, > if consumed use eina_binbuf_remove().]] the given binbuf is the internal one used for reading. That is, on construct a new binbuf is created (with either fixed capacity or grow-able, depending on given options). Data is read directly to the end of this buffer using recv() and the likes (with amount of left memory). Once the the user takes/consumes that memory, he must call eina_binbuf_remove(buf, 0, read_amount). This automatically free's up space for future reads. This also allows peek (read without consuming), like check if there is a '\n' in there. If there are none, just do not consume anything. If a fixed capacity buffer is used, then if the limit is reached, the fd will stop to be watched and a timer/job/animator/whatever is used to periodically inform the user about data. This should be less pressure on the main loop than keeping the fd triggering incoming data. In these scenarios data should be either discarded (call binbuf reset()) or copied elsewhere (but then why use a fixed buffer? so not a real use case). If a growable buffer is used, a minimum free size is enforced before every call to recv(), this provides a balance between memory consumption and number of recv() calls to be executed. Note all of this is nicely hidden inside Ecore_Con (Efl.Net.Socket), all the user needs to do is to consume data from a binbuf! ------------------------------------------------------------------------------ _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel