I think that I didn't explain myself correctly.

Let me try again.

I'm writing a C library, and I want it to be useful not only in Linux
userland, but also in other contexts, such as embedded devices, and inside
the Linux kernel.

This library sometimes allocates memory.

If I'll just allocate memory with malloc, my library wouldn't even compile
with embedded devices. Hence, I'll receive an allocator function from the
user, and use it to allocate memory.

A concrete example, a "regular" read_line function

char *read_line(struct reader *r) { char *rv = malloc(len); read_to(rv);
return rv; }

A more flexible read_line function:

char *read_line(struct reader *r, struct mem_pool *pool) { char *rv =
pool->alloc(pool, len); read_to(rv); return rv; }

Now I'm fine, because I can define pool->alloc to be kmalloc in the kernel
context, or use preallocated pools in embedded device.

What should I do if memory allocation fails? I can return an error for the
user, but it makes the API more complicated. Since many functions would
have to return error just in case of memory allocation failure.

Our read_line example would now look like

struct error read_line(struct reader *r, char **line);

And users would have to check error at each invocation.

I think I can avoid that. What do I intend to do?

My library would assume each memory allocation is successful, and the
client that provides the memory allocator would be responsible to failure
handling.

For example, in a "regular" linux userspace program, the mem_pool would be
something like

void *linux_userspace_mem_pool(struct mem_pool *pool, int size) {
   void *rv = malloc(size);
   if (rv == NULL) {
       syslog("ENOMEM");
       exit(0);
   }
}

An embedded client could throw an exception, or longjmp to the main loop,
or reset the system.

Now my question is, is that a reasonable behavior that would suite embedded
devices. I do not have enough experience to know that. Indeed, since I'm
writing a library that I hope would serve as broad audience as possible, it
is hard to know the requirements in advance.

Hence, I think 1-4 are already addressed, I always gives the user control
what would happen when he's out of memory.

Regarding 5-6. What I'm saying is, seeing malloc returning NULL in
production is very rare. I personally never seen that. I think that the OOM
killer would wreck havoc to the system before it would happen, hence,
crashing when malloc returns NULL is a reasonable behavior.

Regarding 7, this does not complicate the allocation API, it complicates my
API, since I'll have functions that cannot fail, generally speaking, but
allocates memory. Those would have to return error, and the user would have
to check the error.

Thanks,


On Sat, May 16, 2015 at 11:18 PM, Oleg Goldshmidt <p...@goldshmidt.org>
wrote:

> Elazar Leibovich <elaz...@gmail.com> writes:
>
> > My question is, should I support the case of malloc failure. On one
> > hand, it complicates the API significantly, but on the other hand it
> > might be useful for some use cases.
>
> This sounds like, can you guys tell me what my requirements are? ;-)
>
> If I understand correctly, you want to provide an alternative (to the
> standard malloc() and friends) mechanism for memory allocation,
> targeting primarily embedded systems. If I am not completely wrong,
> consider the following:
>
> 1. Is "mechanism" the operative word? If so, then you should leave
>    *policies* - including exception handling - to the client. If you
>    intend to restrict your library to a single OOM excepton policy you
>    should document the restricton. E.g., if your policy is going to be
>    "segfault" or "commit a clean(ish) seppuku", you should tell
>    potential users, using big bold red letters, "if this doesn't suit you
>    don't use the library."  How much this will affect your library's
>    usefulness/popularity I don't care to predict.
>
> 2. Naively, I cannot imagine *not* letting clients of a
>    production-quality library decide what to do, if only to write
>    something sensible to a log using the client's preferred format and
>    destination. Some 20 year ago I saw popular (numerical) libraries
>    whose authors (probably members of the academia) considered abort a
>    legitimate way of handling failures. A scientist running a numerical
>    application with the ultimate purpose of writing a paper certainly is
>    justified in thinking that way. We, however, disqualified those
>    libraries for any production use for that reason alone, regardless of
>    their other qualities. IIRC we liked one of them enough to find *all*
>    the places where it aborted and modify the code (FOSS rules, huh?).
>
> 3. There are enough examples of custom allocators. I am sure you can
>    find an awful lot of code, say, overriding new/delete in C++. Even
>    the standard libraries provide for overriding allocators. Find a few
>    reputable example, see how exceptions are handled, follow the
>    pattern? I suspect in most cases it is left to the library clients
>    (arguably easier with longjumping exceptions than with C-style error
>    propagation, but the point is, library code does not decide,
>    usually).
>
> 4. What *are* your requirements? If a git client (an example you cited)
>    tries to malloc, gets NULL, tries to recover, and then gives up and
>    dies writing something to stderr, that's one thing. An embedded
>    device just crashing without telling anyone what's wrong? Maybe a
>    different kettle of fish altogether. Do you target devices with
>    limited or somewhat limited - resources? May make a difference.
>
> 5. You mentioned swapping. That does not mean you are out of memory
>    (malloc does not fail whan you swap pages). But I am sure you know
>    that.
>
> 6. Kernel's OOM killer mechanism is also not directly related to
>    malloc() failing. It means that *some* process, not necessarily (or
>    even likely) the process that is requesting memory at the moment,
>    will be killed, according to some policy. No one can decide in
>    advance whether killing *something* is a good decision in an
>    unspecified embedded system.
>
> 7. Why do you say handling failures will complicate the API a lot? It is
>    not clear from what you wrote. After all, malloc() is not more
>    complex because it can return NULL, is it? So can your alloc() member
>    - what's the problem?
>
> --
> Oleg Goldshmidt | p...@goldshmidt.org
>
_______________________________________________
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il

Reply via email to