i am always a bit of jerk about these things because i constantly work with genuinely performance critical code, but the very first thing puts me off:
uv_loop_t* loop = uv_loop_new();
does the compiler know where this exists, is it allocated on demand, is there a lock involved? i hope to get the good answers to these questions but the naming of the function alone makes me skeptical. this skepticism turns out to be justified.
digging in:
loop = (uv_loop_t* )malloc(sizeof(uv_loop_t));
so the answers to all of my questions are the wrong ones for me. i might override the allocator to be less rubbish in my context. but simple things like this tell me that this library was not architected for the kinds of performance considerations that i need to make.
at this high level its not so important, but the more digging i do the 'worse' it gets...
generally this does look helpful, but it gives me nothing over my existing solutions (in my context) which, for example, require zero run-time memory allocations - outside of OS level API calls that I have zero control over - and lean heavily towards lockless implementations, avoiding the massively (but understandably) heavyweight OS provided threading primitives...
thread safety of malloc and other standard library (i.e. libc) type stuff is, in reality, up to the implementor. even when things have no requirement to be thread safe implementors (Microsoft) will often insert what i call 'sledgehammer thread safety' to protect bad programmers from themselves. i can understand why, but it prevents me from being able to use these libraries.
when i can do a better job than your standard library, you have failed imo. but it is just my opinion...
Libuv author here. Libuv doesn't try to be all things to all people - its main users are Node.js and Rust - but if you have suggestions on how to improve the API or the implementation, please file issues[1] or join us in #libuv on irc.freenode.org. We welcome outside input.
As a bit of history, the reason why uv_loop_new() mallocs memory for the struct (and it's something of an anomaly in that respect, most other API functions don't) is that the thing that came before libuv, libev, worked like that. It's something we can change if there is demand for it.
In general, you can always do a better job than any given library for your specific use case. That might mean 10x more work though, it's all about choices/compromises.
That would be my preference. And contrary to what others thought that one would want a lot of these loops, when you want only a few, especially when those few are fixed for the entire program life you can do better by avoiding malloc altogether.
Could be my preference for working on systems that never malloc and only use specific pools and rely on knowing their exact memory requirements from the start to the end. I can acknowledge that this may be more anal than normal but then if the library didn't allocate in my name I could choose to allocate on heap or use it in a static fashion as I please.
As an undergrad I was thought about ADT (Abstract Data Type) and then the "proper" way was to provide a _new method to allocate the data. This also allowed to completely hide the type as the C header didn't need to show the content of the struct being allocated.
If you go with not malloc'ing internally then you need to expose the entire struct and I tend to go about it by using an extra header X_internal.h that is explicitly showing the internals but expects you not to abuse this knowledge.
It's a tradeoff and I currently tend towards the second option more often than not.
Various parts of libuv (e.g. the recv path) have pluggable allocators. I'm more interested in why you'd be wanting to create and destroy event loops at a high rate? That seems to imply you're perhaps creating and destroying threads at a high rate, in which case, you have bigger problems than malloc.
My theory: The library was designed for Node.js, not for ultimate performance. Design for Node.js means "easy to create bindings for", which means opaque pointers instead of structs in the API.
Just wondering if you could recommend some books or open source code that you'd consider to be a good role model of the kind of code you write. I use libuv in one of my projects and I was using it to better my C skills. I don't get to do C very much in my day job. But I'd like to be exposed to different styles of C so that I might understand why one style is used over another in a given context. Thanks.
this is part of the problem. most of it is locked away in proprietary source codes - something i am hoping to fix in the coming months by putting something into the public domain myself. :)
Genuine question: why would you want to create a significant numbers of loop contexts? (Your way does sometimes save one pointer dereference, but that's not what you appear to be talking about.)
uv_loop_t* loop = uv_loop_new();
does the compiler know where this exists, is it allocated on demand, is there a lock involved? i hope to get the good answers to these questions but the naming of the function alone makes me skeptical. this skepticism turns out to be justified.
digging in:
loop = (uv_loop_t* )malloc(sizeof(uv_loop_t));
so the answers to all of my questions are the wrong ones for me. i might override the allocator to be less rubbish in my context. but simple things like this tell me that this library was not architected for the kinds of performance considerations that i need to make.
at this high level its not so important, but the more digging i do the 'worse' it gets...
generally this does look helpful, but it gives me nothing over my existing solutions (in my context) which, for example, require zero run-time memory allocations - outside of OS level API calls that I have zero control over - and lean heavily towards lockless implementations, avoiding the massively (but understandably) heavyweight OS provided threading primitives...
thread safety of malloc and other standard library (i.e. libc) type stuff is, in reality, up to the implementor. even when things have no requirement to be thread safe implementors (Microsoft) will often insert what i call 'sledgehammer thread safety' to protect bad programmers from themselves. i can understand why, but it prevents me from being able to use these libraries.
when i can do a better job than your standard library, you have failed imo. but it is just my opinion...