_eo_pointer_error() was kinda a bitch to debug as it provided a nice
breakpoint location, but did not provide a good output since the file,
line and function were always the same.
Change that to be a thin wrapper on top of eina_log_vprint(), then we
keep the breakpoint location yet provide useful information.
In that sense, change other error messages so they carry as much
information as possible.
Normally when debugging Eo with gdb you can just use any of the internal
eo functions to resolve the id to its internal pointer. However, when
loading a coredump you can't execute any code, not even the id resolve
code.
This change adds a gdb function that resolves the id to its pointer form
without executing any code in the process space. This plugin is
essentially the id resolve code written in python as a gdb function.
Usage:
Print the pointer:
(gdb) print $eo_resolve(obj)
$1 = (_Eo_Object *) 0x5555559bbe70
Use it directly (e.g. to print the class name):
(gdb) $eo_resolve(obj)->klass->desc.name
This plugin requires that the coredump would be loaded with the exact
same libeo.so binary (or at least one that hasn't changed eo internals),
and that the debug symbols for libeo.so would be available for gdb to
use.
Note:
This feature is incomplete and only resolves IDs that are owned by the
main thread and in the main domain. This is not a big issue at the
moment, because almost all of our IDs are like that.
@feature
When resolving a function for an object the object would get reference,
and then in some failure cases won't be freed.
I suspect this is a regression following the reshuffling that was done
in that function recently.
Thanks to zmike for investigating and reporting this.
Fixes T4740
@fix
This happens with shared objects.
The situation seems to be:
1. object has composited object a of class A in thread 1
2. call something on object a from thread 2, deadlock
In fact, do anything from thread 2 on a shared object and you deadlock.
this moves a lot of error case handling into goto's so the code gets
out of the hot path and this should help expecially since variou
smacros do things like:
do { char buf[256]; sprintf(buf, fmt, ptr); _eo_pointer_error(buf); } while (0)
_Efl_Class *klass; \
do { \
klass = _eo_class_pointer_get(klass_id); \
if (!klass) { \
_EO_POINTER_ERR("Class (%p) is an invalid ref.", klass_id); \
return ret; \
} \
} while (0)
so putting quite a chunk of code inside a rare "if this errors"
handler that will cause l1 cache misses and this we don't want, thus
moving stuff in eo core out of hot paths to cut down on overhead. yes
it might not be pretty but it's kind of the right thing at such a core
level of efl. this also does the same to the eo base class as this is
also going to be relatively hot given it's the core of every other
object.
so there were a few issues. one we had a spinlokc on the eoid table
for shared objects AND then had a mutex for accessing those objects
(released on return from any eo function). BUT this missed some funcs
like eo_ref, eo_unref and so on in eo.c ... oops. so fixed. but then i
realized there was a race condition. we locked the eoid table then
unlocked with our pointer THEN locked the sharted object mutex ...
then unlocked it. that was a race condtion gap. so we should share the
same lock anyway - if it's a shared object, grab the shared object
mutex then do a lookup and if the lookup does not fail, KEEP the lock
until it is released by the return from eo function or by some special
macro/funcs that released a matching lock. since its a recursive lock
this is all fine. as its also a universal single lock for all objects
we just need the eoid to know if it's shared and needs locking based
on the domain bits. so now do this locking properly with just a single
mutex, not both a spinlock and mutex and keep the lock around until
totally done with the object. this plugs the race condition holes and
goes from 1 spinlock lock and unlock then a mutex lock and unlokc to
just a single mutex lock and unlock. this means shared objects are
actually truly safe across threads and only have the overhead of a
single recursive mutex to lock and unlock in every api call.
Summary:
as told in _eina_stringshared_key_cmp in eina_hash.c:
originally we want to do this:
return key1 - key2;
but since they are ptrs and an int can't store the different of 2 ptrs in
either 32 or 64bit (signed hasn't got enough range for the diff of 2
32bit values regardless of their type... we'd need 33bits or 65bits)
So changing this to the same logic.
Reviewers: tasn, raster
Subscribers: cedric, jpeg
Differential Revision: https://phab.enlightenment.org/D4298
This change lets us remove a field from the structure that leads to
around 20KiB more of saving in private dirty pages in elementary.
This also looks a bit better and feels a bit cleaner.
Breaks API and ABI.
Before this commit, function overrides were explicit. That is, you'd
have to explicitly state you were overriding a function instead of
creating a new one. This made the code a tad more complex, and was also
a bit more annoying to use. This commit removes this extra piece of
information.
This means we now store much less information per function, that will
let us further optimise out structures in the future.
Now that we have recursive locks, the class creation code can be much simpler.
All the code there was essentially our own implementation of recursive locks,
or rather a special case of those.
This is no longer needed.
this adds a signle mutex (recursive) mutex for all eo objects that is
auto-called by _efl_object_call_resolve() and _efl_object_call_end()
that wrap all eo method calls and since its recursive it can be
blindly called for sub-calls. this will lock all shared objects during
any call to any shared object so only the thread calling now has
access until it releases. not fine-grained but good enough and the
best we can do "simplistically".
This moved all the eoid tables, eoid lookup caches, generation count
information ad eo_isa cache into a TLS segment of memory that is
thread private. There is also a shared domain for EO objects that all
threads can access, but it has an added cost of a lock. This means
objects accessed outside the thread they were created in cannot be
accessed by another thread unless they are adopted in temporarily, or
create4d with the shared domain active at the time of creation. child
objects will use their parent object domain if created with a parent
object passed in. If you were accessing EO (EFL) objects across threads
before then this will actually now cause your code to fail as it was
invalid before to do this as no actual objects were threadsafe in EFL,
so this will force things to "fail early".
ecore_thread_main_loop_begin() and end() still work as this uses the
eo domain adoption features to temporarily adopt a domain during this
section and then return it when done.
This returns speed back to eo brining the overhead in my tests of
lookup for the elm genlist autobounce test in elementary from about
5-7% down to 2.5-2.6%. A steep drop.
This does not mean everything is perfect. Still to do are:
1. Tests in the test suite
2. Some API's to help for sending objects from thread to thread
3. Make the eo call cache TLS data to make it also safe
4. Look at other locks in eo and probably move them to TLS data
5. Make eo resolve and call wrappers that call the real method func do
recursive mutex wrapping of the given object IF it is a shared object
to provide threadsafety transparently for shared objects (but adding
some overhead as a result)
6. Test test est, and that is why this commit is going in now for wider
testing
7. Decide how to make this work with sending IPC (between threads)
8. Deciding what makes an object sendable (a sendable property in base?)
9. Deciding what makes an object shareable (a sharable property in base?)
This is another follow up to the investigations of T4227. As stated
there, in any PIE (a shared library is one), structures, even const ones
end up being written to because of dynamic relocation. This means that
using static const structures has actually lead to no savings, only
waste. Since we never really needed them, using them made things even
worse than just having a different API that doesn't save them.
Thus, this commit changes the way we set the functions. Instead of
passing a pre-populated struct, we now just have an initialiser function
where you set the functions. This on its own doesn't significantly reduce
the amount of dirty memory pages for a reason I have yet to uncover,
though I believe it's done as a misguided compiler optimisation.
However, this design is flexible enough so we can change to another one
that is quite ugly, but I have already tested and proven that does that.
This patch series doesn't include the better improvement (passing
everything on the stack as va_args) because the API was too ugly
for me to bear, and I would rather first make sure there is no way to
force the compiler to do the right thing here.
Unfortunately this commit gives up on useless stricter validation.
Before this commit we would make sure that we are only overriding
functions correctly defined in our hierarchy. With this one, we don't
anymore. This is not a big problem though because this is a check that
is also enforced by Eolian. So as long as you are using Eolian, you
should be fine.
Breaks API and ABI!
@feature
This improve speed of processing events in genlist scrolling benchmark by 30%
inside the efl_object_event_callback_call code. Not a really big deal as it
goes from 0.9% to 0.6% of the total time spend. Welcome to micro optimization.
Rename the type to something more sensible and change it to remove the
last remanent of Eo1. This fixes a fixme that has been there for a
while.
The type doesn't really matter, it just looks nicer with the va_list.
This commit implements a sort of CoW for the vtables. The vtables are
usually just linked to and refcounted. When we need to change them we
allocate new ones and copy them over so we can write to them.
I wrote some code to measure the effectiveness of this change. When
running elementary_test (and immediately exiting) I saw that out of the
total number of vtable chains (561) that were needed by the classes in
the EFL, 79 (14.08%) were reused. Considering that I had to add
refcounting (unsigned short, but let's consider it's the size of a word
because of alignment), I would calculate the saving as such (in bytes):
Number of items in a chain (refcounted block): 32
32 bit:
sizeof(chain_node) = 8
Mem wasted on refcounting: 561 * 4 = 2244
Mem saved because of sharing: 79 * (32 * 8) = 20224
Total save: 17980 bytes
64 bit:
sizeof(chain_node) = 16
Mem wasted on refcounting: 561 * 8 = 4488
Mem saved because of sharing: 79 * (32 * 16) = 40448
Total save: 35960 bytes
Wow, we use a lot of memory in Eo classes, I'm sure we can
save even more if we put our hearts into it (change the shareable units
to be smaller to increase the chance of sharing).
This is internal and doesn't affect API/ABI so we can change this even
further with time.
This also improves efl_object_override(). This should now be quite
memory efficient (don't abuse, but it's not a big hogg as it was), so
feel free to abuse that one and rely on it in API.
@feature
ok. so here's the issue at least now. we have eo objects in the canvas
and they have a refcount of 2 user_refcount is 0. the calls stack does
NOT show we are calling callbacks at that time on these objects. they
are not in the backtrace (the canvas is, the objects themselves are
not).
SOMETHING is keeping 2 eo "internal" refs on these objects and i have
no idea what/how/who. it's a royal pain in the butt to find out as the
only way is lots and lots of logging and you get drowned in the
logging...
so what I have now done is a super ugly workaround that detects these
zombie objects that refuse to die and just FORCES them to die when the
evas canvas frees and clears out layers.
ac10a00acc doesn't really cause the
issue, it just brings it out in the open for all to see far more
easily. but something is deeply wrong SOMEWHERE with SOME objects and
our refcounts.
this fixes T4187
This is a (minor) API & ABI break in Eo.h!
I say minor as eo_override shouldn't be used yet (EO is unstable
and this patch includes all the use cases in EFL).
I'm not very happy about the new form of the macro, but it avoids
two things:
- passing in a struct (valid in C, but never used in EFL)
- using a GCC construct to create structs on the fly
It was inspired by the event array define, but I don't think
we need the runtime memcpy here.
See also:
https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html
eo_override would leak the vtable if called multiple times, this
fixes that. Also, it is now possible to revert back to the original
class' vtable by passing in { NULL, 0 }
I believe it is thus possible to incrementally override more
functions on an object. Absolutely not recommended, but should work.
But it is not possible to selectively revert back to the original
class implementation on a single method. Use eo_super for that,
or revert back the entire object overrides.
PS: Is it normal that we pass in a struct? We never do that in EFL...
When using eo_add_ref, it was increasing the refcount before the user
context in the addition has fully ended. This means the object had its
reference increased while still not finalized, which means it was
sometimes passed with an increased refcount to unsuspecting class code.
The correct behaviour is to increase the reference count just before
returning the object to the user at the end of eo_add so the reference
count is only increased for whoever asked for it.
Breaks ABI!
@fix
This commit changes the way refcount is dealt with internally. Before
this commit, there was one refcount shared between Eo internals and
users. Now there is a refcount for eo operations (like for example,
function calls) and one for user refcount (eo_ref).
An example bug that this protects against (which is seemingly rather
common) is:
some_eo_func(obj);
// Inside the implementation of that func:
pd->a = 1; // The object's private data
eo_unref(obj); // To delete the object
eo_unref(obj); // A big one extra unref
pd->a = 2; // Segfault, this data has already been freed
This is a feature, but really just a fix for a class of bugs.
@feature
I was getting a crash in eo_shutdown, inside
_efl_event_pointer_class_destructor as I was calling eo_del
from there. But the parent class was already destroyed.
Assuming class IDs can only go up, and child classes are only
instanciated after all their parents, it is safer to call the
class destructors in reverse order.
Obviously, still pretty sure eo_del() in a class_destructor
is not a good idea...
This was needed when the eo composite object was still in beta. Since commit
d7c45e41d4 this is no longer the case. No beta
part left in eo base so we can safely remove this define.
We used to keep a reference to the parent object and have it in the call
structure although we were actually calling the function on the embedded
object. This was needed because we wanted to unref the parent correctly.
This was incorrect (and marked as a hack) and now I finally gotten
around to implementing the (amazingly simple) fix to remove this
workaround.
Essentially we just ref the comp object, unref the parent, and let the
normal eo call flow to unref the comp object correctly later on, like it
would have unreffed the extra ref we had for the parent.
This reverts commit 546ff7bbba.
It seems that eo_del() is useful and removing it was creating bugs.
The issue is that the way we defined parents in eo, both the parent and
the programmer share a reference to the object. When we eo_unref() that
reference as the programmer, eo has no way to know it's this specific
reference we are freeing, and not a general one, so in some
circumstances, for example:
eo_ref(child);
eo_unref(child); // trying to delete here
eo_unref(container); // container is deleted here
eo_unref(child); // child already has 0 refs before this point.
We would have an issue with references and objects being freed too soon
and in general, issue with the references.
Having eo_del() solves that, because this one explicitly unparents if
there is a parent, meaning the reference ownership is explicitly taken
by the programmer.
eo_del() is essentially a convenience function around "check if has
parent, and if so unparent, otherwise, unref". Which should be used when
you want to delete an object although it has a parent, and is equivalent
to eo_unref() when it doesn't have one.
so... i got this ... callback calls callback calls something calls
callback that deletes the original object at the top so when it comes
back ... things die as the object was destructed. in removing eo_do()
we removed the ref/unrefs that went with it. so this uses the
_EO_API_BEFORE_HOOK and _EO_API_AFTER_HOOK to call exposed "internal"
public functions _eo_real_ref() and _eo_real_unref().
this fixes a new segv i've noticed in several e dialogs where hitting
close does the above via callbacks and closes the window etc.
This change lets you override the functions of objects so that those
functions will be called instead of the functions of the class. This
lets you change objects on the fly and makes using the delegate pattern
easier (no need to create a class every time anymore).
You can see the newly added tests (in this commit) for usage examples.
@feature
We used to have eo_del() as the mirrored action to eo_add(). No longer,
now you just always eo_unref() to delete an object. This change makes it
so the reference of the parent is shared with the reference the
programmer has. So eo_parent_set(obj, NULL) can free an object, and so
does eo_unref() (even if there is a parent).
This means Eo no longer complains if you have a parent during deletion.
This was done following a feature request by @raster. There was no real
reason for it not to be an eo function and this gives us more
flexibility.
The reason why this done was to provide a way for classes to do special
things when an object deletion was requested, for example in the case of
Evas, hide the object.
so memory for class id -> ptrs is mallocs. this means it likely will
be next to other memory malloced. which means overrunning memory
someone mallocs could walk into the class table and corrupt it. we put
eo ids in mmaped regions to avoid this if possible in case of buggy
code. let's do it for classes too.
this also now allocs in larger chunks. for mmap its in page chunks
(which can hold either 1024 or 512 classes depending on 32 or 64bit).
reallocs still work if mmap is not there and we do them in chunks of
128 classes (it seems that we start at about 70 or so classes atm when
elm_test starts and it grows to ~100 or let's do 128 as that's pretty
much our base as a power of 2 and we now dont realloc much).
I'm reverting this because according to jpeg it was possibly fixed in
5284b62e93.
I reverted this patch after his fix and followed his reproduction cases
and it seems that his second patch does indeed fix this issue so this
patch is no longer needed.
This reverts commit 0862b9d083.
It seems that calling a @class function with an EO object
(that was not the required Eo_Class) lead to a situation
where func->func was NULL. And that meant a crash after
call_resolve.
The proper fix is to properly call a @class function with a
class object.
The current eo_add uses a (very useful) gcc extension that is only
available in gcc compatible compilers (e.g clang). Until this commit we
just temporarily ignored this fact. This adds a fallback implementation that
can be used interchangeably with the non portable one. This means that the
same binary can call either at any point in time and the code will work.
Breaks ABI.
Imagine this. You have an object. You pass this object handle as a
message to another thread. Let's say it's not a UI object, so
something you might expect to be able to be accessed from multiple
threads. In order to keep the object alive you eo_ref() it when
placing the message on a queue and eo_unref() it once the message is
"done" in the other thread. If the original sender unref()ed the
object before the message is done, then the object will be destroyed
in the reciever thread. This is bad for objects "expecting" not to be
destroyed outside their owning thread.
This allows thius situation to be fixed. A constructor in a class of
an object can set up a delete interceptor. For example if we have a
"loop ownership" class you multi-ple-inherit from/use as a mixin. This
class will set up the interceptor to ensure that on destruction if
pthread_self() != owning loop thread id, then add object to "delete
me" queue on the owning loop and wake it up. the owning loop thread
will wake up and then process this queue and delete the queued objects
nicely and safely within the "owning context".
This can also be used in this same manner to defer deletion within a
loop "until later" in the same delete_me queue.
You can even use this as a caching mechanism for objects to prevernt
their actual destruction and instead place them in a cached area to be
picked from at a later date.
The uses are many for this and this is a basic building block for
future EFL features like generic messages where a message payload
could be an eo object and thus the above loop onwership issue can
happen and needs fixing.
This adds APIs, implementation, documentation (doxy reference) and tests.
@feature
The syntax is described in: https://phab.enlightenment.org/w/eo/
Summary:
eo_do(obj, a_set(1)) -> a_set(obj, 1)
eo_do_super(obj, CLASS, a_set(1)) -> a_set(eo_super(obj, CLASS), 1)
eo_do_*_ret() set of functions are no longer needed.
This is the first step, the next step would be to also fix up eo_add()
which currently still uses the old syntax and is not 100% portable.
@feature
Until now it wasn't allowed/possible to init (eo_init) eo after it has
been shut down (eo_shutdown). This commit fixes that, so now that is
fully legal to have as many init/shutdown cycles as you want.
There was a previous workaround for this issue:
e47edc250d.
This should allow more flexibility when using the EFL in loadable
modules and in various other scenarios.
The problem is that the class_get() functions cache the previously
created class for efficiency, but the class is freed if eo is shut down,
so the cached pointer is actually invalid.
The solution to the problem was to maintain a generation count
(incremented every time we shut down eo), and compare that to a locally
saved version in class_get(). If they don't match, recreate the class,
as it has already been freed.
@feature
This commit was a workaround to let us shutdown and then init eo without
any issues. It leaks and it's wrong. This will properly be fixed in the
next commit.
This reverts commit e47edc250d.
This is not really needed, I just did it to make it easier for coverity
(and future static analysers) to understand that the class id doesn't
need to be accessed with a lock.
CID1341854
Currently, eo_shutdown can't work.
Every Eo_Class ID is stored inside its class_get() function as a
static variable. This means any call to class_get() after eo_shutdown()
(even if eo_init was done properly) will lead to using an invalid ref
for the class id. In other words, the class is not valid anymore,
and objects can't be created.
Resetting the pointer to NULL would be possible, if we passed it
during the class creation. But this would lead to potential crashes
if a class was created from a now dlclosed library.
The only solution I can envision here is to check that class_get
actually returns a valid ref with the right class name. Most likely
the performance impact is not acceptable.
This fixes make check for me (with systemd module for ecore).
This is faster in most cases, and to be honest, should be much faster
than it is. I don't understand why there's no better directive to mark a
variable as *really* important thread storage that is used all the time.
We don't really need the eo_id most of the time, and when we do, it's
very easy to get it. It's better if we just don't save the eo_id on the
stack, and just save if it's an object or a class instead.
It seems that the idea behind that optimisation, is to save object data
fetching when calling functions implemented by the object's class inside
functions implemented by the object's class. This should be rare enough
not to worth the upkeep, memory reads and memory writes, especially
since for all cases apart of mixins (for which this optimisation won't
work for anyway), the upkeep is more costly than fetching the data
again.
removing the klass member meant removing hooks and keeping cache small
but that meant not using it. this meand if the object is not an obj...
i removed the:
call->obj = _eo_class_id_get(call->klass);
line - seemed harmless/pointless. apparently not. so put it back but
use the klass there in local vars and not in call as it's not there
(and not needed).
fix.
we pass both the callcache and the op id - both are static and filled
in at runtime, so merge them into the same struct. this should lead to
better alignment/padding with the offset array and the next slot and
op fields, probably saving about 4-8 bytes of rame per method with no
downsides. also pass in only cache ptr, not both cache ptr and opid -
less passing of stuff around and should be better.
BEWARE! this breaks eo ABI. _eo_call_resolve and _eo_data_scope_get
are 2 of the biggest cpu users in eo. they easily consume like 10-15%
cpu between them on tests that drive a lot of api - like simply
scrolling a genlist around. this is a lot of overhead for efl. this
fixes that to make them far leaner. In fact this got an overall 10%
cpu usage drop and that includes all of the actual rendering, and code
work, so this would drop the eo overhead of these functions incredibly
low. using this much cpu just on doing call marshalling is a bug and
thus - this is a fix, but ... with an abi break to boot. more abi
breaks may happen before release to try and get them all in this
release so we don't have to do them again later.
note i actually tested 4, 3, 2, and 1 cache slots, and 1 was the
fastest. 2 was very close behind and then it got worse. all were
better than with no cache though.
benchmark test method:
export ELM_ENGINE=gl
export ELM_TEST_AUTOBOUNCE=1
while [ 1 ]; do sync; sync; sync; time elementary_test -to genlist;
sleep 1; done
take the 2nd to the 8th results (7 runs) and total up system and user
time. copmpare this to the same without the cache. with the cache cpu
time used is 90.3% of the cpu time used without - thus a win. at least
in my tests.
@fix
so we do a bit of error handling like does a stack fail to allocate,
does setting the tls var fail, have the stack frames been nulled or
not allocated, etc. - these acutally cost every call because they mean
some extra compare and branches, but ore because they cause a lot fo
extra code to be generated, thus polluting instruction cache with code
and cacheline fetches of code that we rarely take - if ever.
every if () and DBG, ERR etc. does cost something. in really hotpath
code like this, i think it's best we realize that these checks will
basically never be triggered, because if a stack fails to grow... we
likely alreayd blew our REAL stack for the C/C++ side and that can't
allocate anymore and has already just crashed (no magic message there -
just segv). so in this case i think this checking is pointless and
just costs us rather than gets us anything.
This causes a significant speed up (around 10% here) and is definitely
worth it. The way it's done lets the compiler cache the value across
different eo_do calls, and across the parts of eo_do. Start and end.
This breaks ABI.
This may look like an insignificant change, but it doubles the speed of
this function, and since this function is called so often, it actually
improves my benchmarks by around 8%.
This breaks ABI in a harmless way, and it will give us the ability to
drastically improve Eo in the future without breaking ABI again, thus
allowing us to declare Eo stable for this release if we choose to.
We use function names instead of function pointers of Windows, because
of dll import/export issues (more in a comment in eo.c). Before this
commit we were comparing the pointers to the strings instead of the
content in some of the places, which caused op desc lookup not to work.
This fixes that.
Thanks to vtorri for his assistance.
@fix
This removes code that became dead in commit:
389c6d35f2
The commit doesn't explain why we don't shrink or grow when using mmap,
but this is how it is. No reason to keep old code there.
CID 1240224
@fix
As described by Carsten in his email to edev ML titled:
"[E-devel] eo stability - i think we need to postpone that"
with the switch to Eo2 we significantly increased our usage of RW memory
pages, and thus significantly increased our memory usage when running
multiple applications.
The problem was that during the migration to Eo2 the op id cache and the
op description arrays were merged, causing the op description arrays to
no longer be RO. This patch enables users of Eo (mainly Eolian) to
declare those arrays as const (RO) again, saving that memory.
There might be performance implications with this patch. I had to remove
the op desc array sorting, and I used a hash table for the lookup. I
think the op desc sorting doesn't really affect performance because that
array is seldom accessed and is usually pretty short. The hash table
is not a problem either, because it's behind the scenes, so it can be
changed to a more efficient data structure if the hash table is not good
enough. The hash table itself is also rarely accessed, so it's mostly
about memory.
Please keep an eye for any bugs, performance or excessive memory usage.
I believe this should be better on all fronts.
This commit *BREAKS ABI*.
@fix
This hasn't been used for a while. Since we are going to break Eo a bit anyway
it's a good opportunity to drop this.
This may cause a slight performance issues with legacy events, such as
smart callbacks. This shouldn't really be a problem as we've migrated away from
them. If it does, we need to migrate the remaining parts. Only relevant
for callbacks that are added before the classes are created, which
shouldn't be possible except for smart, only for old evas callbacks.
After this change, parent_set assigns a ref, so for example:
obj = eo_add(CLASS, parent); /* Ref is 1 */
eo_do(obj, eo_parent_set(parent2)); /* Ref is 1 */
eo_ref(obj); /* Ref is 2 */
eo_do(obj, eo_parent_set(NULL)); /* Ref is 1, giving the ref to NULL */
eo_do(obj, eo_parent_set(parent)); /* Ref is 1 */
This is following a discussion on the ML about commit
8689d54471.
@feature
@fix
XXX: Given EFL usage of objects, construction is a perfectly valid thing
to do. we shouldn't complain about it as handling a NULL obj creation is
the job of the caller. a perfect example here is ecore_con and ecore_ipc
where you create a con or ipc obj then set up type/destination/port and
the finalize of the constructor does the actual connect and thus this
fails or succeeds based on if service is there.
until there is a better solution - don't complain here.
This is heavily based on a patch by Vincent Torri. I just refactored it
a bit so it doesn't break ABI on Linux, only on Windows (where it was
broken anyway).
This patch changes things so on Windows, functions are looked up only
based on their name. Because of the indirection (and export/import
tables) windows does, this is the only reasonable way to make it work.
You should always use curly brackets. Especially when the inside statement
has its own curlys. This can be confusing and has already lead to bugs in
many projects.
While unrefing twice works, it's cleaner to unref the ref we
have and delete normally. It will handle parnet detachments in
a nicer way, and is just more correct.
This is another cleanup in perparation for the Eo stable release.
This is no longer needed thanks to the proper error reporting with
eo_constructor()'s new return value.
The finalizer change cleans it up a bit so it catches more cases/issues.
This also means that the finalizer cleans up the object in all cases,
and not only some.
@feature.
From now on, constructors should return a value, usually the object
being worked on, or NULL (if the constructor failed). This can also
be used for implementing singletons, by just always returning the same
object from the constructor.
This is one of the final steps towards stabilizing Eo.
@feature
As discussed on IRC and ML. We are in a feature freeze phase, and this
patch is not essential. Furthermore, this patch was never discussed.
This reverts commit 537c7fe9e3.
This affects eo_do() and eo_add() that used to use the ({}) GCCism.
Following a discussion with Peter de Ridder after my talk at FOSDEM,
we've decided to reopen the GCCism (works with other gcc compatible
compilers like clang and intelc) discussion, and after a bit of back and
forth it was decided to make things more portable, at the cost of ease
of use.
For example:
if (eo_do(obj, visible_get()))
is no longer allowed, the portable alternative
Eina_Bool tmp;
if (eo_do_ret(obj, tmp, visible_get()))
is to be used instead.
However:
eo_do(obj, a = a_get(), b = b_get(), bool_set(!bool_get))
are still allowed and OK.
eo_do(obj, if (a_get()) return;);
is no longer allowed, but:
eo_do(obj, if (a_get()) something());
is still allowed.
For clarity, this commit only incorporates the Eo changes, and not the
EFL changes to make the efl conform with this change.
Thanks again to Peter de Ridder for triggering this important discussion
which led to this change.
The header.id was masked before using it as index in the _eo_classes
array and was not unmasked when used.
It hasn't caused segfault (by sheer luck) but was wrong.
@fix
So I don't really understand why the code was not there before, but it resulted
in my experiment of making a combobox for elementary just impossible. Now it
work at least.
For some reason, they were normal functions instead of eo functions,
which makes them harder to bind, less safe, and just wrong.
This commit fixes that.
Now it's more clear and consistent. This commit complements the previous
eo_add commit (a7560dbc61).
Now eo_add should be matched with eo_del
eo_ref with eo_unref
eo_add_ref with eo_unref + eo_del
Essentially, the change is that if you have the ref to an object, you
need to unref it. Thus making ref/unref unneeded for most people who use
things (carefully) in c. If however, you would like to delete an object
previously created by you, you should eo_del (counter-part to eo_add).
It's still recommended you ref/unref when dealing with objects in
scopes, as you can't know when an object might just get deleted as a
by-product of another call.
This fixes an issue found by JackDanielZ.
Before this change eo_add() used to create an object with 1 ref, and if
the object had a parent, a second ref.
Now, eo_add() always returns an object with 1 ref, and eo_add_ref()
preserves the old behaviour (for bindings).
eo_unref now un-parents if refcount is 0, and eo_del() is an alias for
eo_unref (will change to be a way to ensure an object is dead and goes
to zombie-land even if still refed).
This moves the mainloop check inside the function. There was never need
for it to be in client code (i.e a header/macro).
This is better suited inside eo_do_start because this is a macro some
bindings have to re-implement, and we definitely don't want it to be any
more complicated than it has to be.
This breaks ABI and makes elm 1.12 depend on efl 1.11. This is not an issue
as because of eolian and interfaces it's already the case.
eina_tls_get is really slow, having a fast path for the main loop does really
help us right now. It is also unlikely that slowing down a little bit the use
of eo in thread is going to have any impact on application speed any time soon.
I win a +10% on expedite benchmark compared to without.
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This enables checking if an object is being created, or has already been
finalized. This is useful in functions that you want to allow
only during the creation phase (i.e inside the eo_add()).
Comp objects are rare, and since we allow using classes as interfaces,
we end up allocating a lot of memory for something we don't even use.
That's why it was a linked list in the first place, and that's why it
should remain a list.
This is almost a complete revert. I reverted the code itself, and the
intent (use of array instead of list), but not the tests, or the new
return value added to comp_detach, which is useful.
This reverts commit ef09ef7489.
This function lets you hook at the end of eo_add and override it for a
class. This is essentially the first step towards killing custom
constructors. Instead of having a custom constructor, you should just
do:
eo_add(CLASS, parent, a_set(3), b_set("eou"));
eo_constructor is called at the beginning for pre-init things.
eo_finalize is called at the end, for actually finalizing and doing
things. This cleans up the API and possibly saves a lot of things that
would have been stupid and slow in the past, like loading an elm widget
with an existing theme, and then changing the theme.
** This breaks Eo ABI, please recompile elementary and everything else that
creates eo objects.
@feature
Match function names when the API pointer is out of range.
Reviewed by TAsn and modified according to his comments :)
Differential Revision: https://phab.enlightenment.org/D876
this fixes and eo2 problem where when callstack grows (or shrinks)
and realloc nas to relocate memory, the frame ptrs like fptr become
invalid and all sorts of hell ensues.
this uses mmap so blowing the stack will segv, not scribble over
memory, also its separated from malloc heap, and now big enough to not
need to size ... ever (1024 entries).
It's now completely valid to do:
a = eo_do(obj, a_get());
or:
b = eo_do(obj, a_set(1), b_get());
Also, the default return value for eo2 functions is now also returned
when the object is invalid, not just when the object does not match
class.
It's a small refactor that fixed both issues at once.
@feature
@fix
create/destroy tls key (_eo2_call_stack_key) at eo_init()/eo_shutdown().
use _eo2_call_stack_get() to allocate the stack when required.
register _eo2_call_stack_free() as eina_tls_cb_new() delete callback.
eo_class_new() returns NULL on error in _eo2_class_funcs_set().
it covers: NULL API func, API redefined, dich func override,
overriding non-existing fct.
as op descs are sorted, we can't output fct indexes in error msgs, but
as they are sorted using api_fct as key, we can detect multiple usage of
the same api_fct which leads to an unpredictable call to whatever is
returned by _eo2_api_op_id_get()->_eo2_api_desc_get().
it is still possible to instanciate an object of a not well defined class.
a mixin class must not inherit
- _eo2_api_desc_get()
accept NULL klass param
EO_CLASS_TYPE_REGULAR_NO_INSTANT is an acceptable extension class type for
- _eo2_class_funcs_set() do not shout if parent is NULL