summaryrefslogtreecommitdiff
path: root/pages
diff options
context:
space:
mode:
authorPaul <pbrown@mykolab.com>2017-11-10 00:21:04 -0800
committerapache <apache@e5-web1.enlightenment.org>2017-11-10 00:21:04 -0800
commitbd24a0f67adb051fbaef7fc0b25f2a1d2db82789 (patch)
treee893f44a728e0d960eaff46660cc47e7bf4bdb06 /pages
parentec2efd1a8285fcd812161a365226c03d1b2b5572 (diff)
Wiki page eo-refcount.md changed with summary [] by Paul
Diffstat (limited to 'pages')
-rw-r--r--pages/develop/tutorial/c/eo-refcount.md.txt35
1 files changed, 26 insertions, 9 deletions
diff --git a/pages/develop/tutorial/c/eo-refcount.md.txt b/pages/develop/tutorial/c/eo-refcount.md.txt
index c1021bc2a..64a9ffe7c 100644
--- a/pages/develop/tutorial/c/eo-refcount.md.txt
+++ b/pages/develop/tutorial/c/eo-refcount.md.txt
@@ -4,7 +4,7 @@
4 4
5# Reference Counting in Eo # 5# Reference Counting in Eo #
6 6
7The previous tutorial ([Introduction to Eo](eo-intro.md)) explained how Eo objects should be created and destroyed in order to avoid *memory leaks*. The present tutorial shows graphically the inner workings of the reference counting mechanism. 7The previous tutorial ([Introduction to Eo](eo-intro.md)) explained how you should create and destroy Eo objects in order to avoid *memory leaks*. The present tutorial shows graphically the inner workings of the reference counting mechanism.
8 8
9To do so, some new *instrumentation* techniques are introduced. These techniques allow collecting information about the state of your program, and, although not frequently used in normal applications, they can be useful for debugging purposes. 9To do so, some new *instrumentation* techniques are introduced. These techniques allow collecting information about the state of your program, and, although not frequently used in normal applications, they can be useful for debugging purposes.
10 10
@@ -77,9 +77,10 @@ efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
77EFL_MAIN() 77EFL_MAIN()
78``` 78```
79 79
80Add a new method before ``_obj_create()`` that uses ``efl_ref_count()`` to print the counts of all the objects in a nice table: 80Add a new method before ``_obj_create()`` that uses ``efl_ref_count()`` to print the counts of all the objects into a nice table:
81 81
82```c 82```c
83[...]
83// Prints status of all our objects in a pretty table 84// Prints status of all our objects in a pretty table
84static void 85static void
85_status_print() 86_status_print()
@@ -90,8 +91,12 @@ _status_print()
90 efl_ref_count(_child1), 91 efl_ref_count(_child1),
91 efl_ref_count(_child2)); 92 efl_ref_count(_child2));
92} 93}
94[...]
93``` 95```
94 96
97> **NOTE:**
98> ``[...]`` in a Code Block indicates existing code which has been excluded for the sake of brevity. There is no need to type ``[...]`` into your program.
99
95And call this method in a couple of interesting places. For example, in your main function (``efl_main()``) after creating all the objects (``_obj_create()``) and after destroying them (``_obj_destroy()``): 100And call this method in a couple of interesting places. For example, in your main function (``efl_main()``) after creating all the objects (``_obj_create()``) and after destroying them (``_obj_destroy()``):
96 101
97```c 102```c
@@ -110,11 +115,11 @@ And call this method in a couple of interesting places. For example, in your mai
110 [...] 115 [...]
111``` 116```
112 117
113What do you think is going to happen if you run this program? Go ahead and try. 118What do you think is going to happen if you run this program? Go ahead and try it.
114 119
115The expected behavior is *undefined*, which usually means your program will abort abnormally (commonly known as *crash*). This is what happened: 120The expected behavior is *undefined*, which usually means your program will abort abnormally (commonly known as *crash*). This is what happened:
116 121
117You can always ask an object for its internal reference count... as long as the object still exists. The problem with the above code is that when a reference count reaches 0, the object is destroyed. If you still hold a pointer to that object (like ``_root`` or ``_child1``) that pointer is *invalid*, and trying to use it as a parameter to any EFL call will result in *undefined behavior*. 122You can always ask an object for its internal reference count... as long as the object still exists. The problem with the above code is that when a reference count reaches 0, the object is destroyed. If you still hold a pointer to that object (like ``_root`` or ``_child1``) that pointer is *invalid*, and trying to use it as a parameter to any EFL call will result in an *undefined behavior*.
118 123
119In summary, the first call to ``_status_print()`` succeeded because the objects where alive, but the second one, after calling ``_obj_destroy()``, crashed because all the objects had been destroyed, and hence their pointers where invalid. 124In summary, the first call to ``_status_print()`` succeeded because the objects where alive, but the second one, after calling ``_obj_destroy()``, crashed because all the objects had been destroyed, and hence their pointers where invalid.
120 125
@@ -131,7 +136,9 @@ To achieve this, EFL uses *Weak References*. The following code snippets explain
131First, add 3 more ``Eo *`` global variables to keep track of the weak references (*wref*'s for short). Put this line below the other 3 global variables: 136First, add 3 more ``Eo *`` global variables to keep track of the weak references (*wref*'s for short). Put this line below the other 3 global variables:
132 137
133```c 138```c
139[...]
134Eo *_root_ref, *_child1_ref, *_child2_ref; 140Eo *_root_ref, *_child1_ref, *_child2_ref;
141[...]
135``` 142```
136 143
137As you can see, wrefs are also regular ``Eo`` pointers; you can use them anywhere you would use an object pointer. 144As you can see, wrefs are also regular ``Eo`` pointers; you can use them anywhere you would use an object pointer.
@@ -152,6 +159,7 @@ Now, replace the previous usage of the plain object pointers in the ``printf()``
152Finally, create the wrefs by adding a call to ``efl_wref_add()`` after each call to ``efl_add()`` in the ``_obj_create()`` method. It should look like this: 159Finally, create the wrefs by adding a call to ``efl_wref_add()`` after each call to ``efl_add()`` in the ``_obj_create()`` method. It should look like this:
153 160
154```c 161```c
162[...]
155static void 163static void
156_obj_create() 164_obj_create()
157{ 165{
@@ -173,6 +181,7 @@ _obj_create()
173 // Add a weak reference so we can keep track of its state 181 // Add a weak reference so we can keep track of its state
174 efl_wref_add(_child2, &_child2_ref); 182 efl_wref_add(_child2, &_child2_ref);
175} 183}
184[...]
176``` 185```
177 186
178Notice how ``efl_wref_add()`` has two parameters: The first one is the object to keep track of, and the second one is a pointer to an ``Eo *`` which will receive the wref. 187Notice how ``efl_wref_add()`` has two parameters: The first one is the object to keep track of, and the second one is a pointer to an ``Eo *`` which will receive the wref.
@@ -217,15 +226,18 @@ Call ``_status_print()`` after returning the ``_root`` reference but before retu
217And now, print the name of the parent of every object in the ``_status_print()`` method, right after printing the reference counts: 226And now, print the name of the parent of every object in the ``_status_print()`` method, right after printing the reference counts:
218 227
219```c 228```c
229[...]
220 printf("Parent: %6s %6s %6s\n\n", 230 printf("Parent: %6s %6s %6s\n\n",
221 _parent_name_get(_root_ref), 231 _parent_name_get(_root_ref),
222 _parent_name_get(_child1_ref), 232 _parent_name_get(_child1_ref),
223 _parent_name_get(_child2_ref)); 233 _parent_name_get(_child2_ref));
234[...]
224``` 235```
225 236
226Now, the ``_parent_name_get()`` method does not exist; you need to create it. It has been moved to a different method because it deals with a few special cases. Add this snippet before ``_status_print()``: 237Now, the ``_parent_name_get()`` method does not exist; you need to create it. It has been moved to a different method because it deals with a few special cases. Add this snippet before ``_status_print()``:
227 238
228```c 239```c
240[...]
229// Retrieves the name of an object's parent, handling special cases like not 241// Retrieves the name of an object's parent, handling special cases like not
230// having any parent, or the object having been already destroyed. 242// having any parent, or the object having been already destroyed.
231static const char* 243static const char*
@@ -238,13 +250,14 @@ _parent_name_get(Eo *obj)
238 // Otherwise, return parent's name 250 // Otherwise, return parent's name
239 return efl_name_get(efl_parent_get(obj)); 251 return efl_name_get(efl_parent_get(obj));
240} 252}
253[...]
241``` 254```
242 255
243Remember you will be calling this method in situations where some of the objects might have already been destroyed. Therefore, the first thing this method does is checking whether the reference count is 0 with ``efl_ref_count()``. In that case it returns a simple dash "-". 256Remember you will be calling this method in situations where some of the objects might have already been destroyed. Therefore, the first thing this method does is check whether the reference count is 0 with ``efl_ref_count()``. In that case it returns a simple dash "-".
244 257
245Remember also that you can do this, because you are using weak references. Passing an invalid pointer to ``efl_ref_count()`` would result in undefined behavior. 258Remember also that you can do this, because you are using weak references. Passing an invalid pointer to ``efl_ref_count()`` would result in undefined behavior.
246 259
247The second thing the method does is checking whether the object has a parent or not by calling ``efl_parent_get()``. If it has no parent, it returns "none". 260The second thing the method does is check whether the object has a parent or not by calling ``efl_parent_get()``. If it has no parent, it returns "none".
248 261
249Finally, the method returns the name of the parent obtained with ``efl_name_get()``. 262Finally, the method returns the name of the parent obtained with ``efl_name_get()``.
250 263
@@ -381,13 +394,14 @@ Finally, notice how the parent of ``_child2`` is not ``_root`` anymore after ``_
381 394
382There's still one more thing you can do with reference counting, and that is being notified when objects are finally destroyed. 395There's still one more thing you can do with reference counting, and that is being notified when objects are finally destroyed.
383 396
384As it is apparent by now, you are aware of the references **you** hold to an object, but, generally speaking, you don't know how many references do other parts of the code hold. Therefore, in some situations it can be complicated to know when an object is **finally destroyed**. 397As it is apparent by now, you are aware of the references **you** hold to an object, but, generally speaking, you don't know how many references other parts of the code hold. Therefore, in some situations it can be complicated to know when an object is **finally destroyed**.
385 398
386If you really need to know, you can register an event callback with ``efl_event_callback_add()`` that will be triggered and that happens. 399If you really need to know, you can register an event callback with ``efl_event_callback_add()`` that gets triggered when that happens.
387 400
388Use it to be notified of the destruction of each object. ``_obj_create()`` should look like this: 401Use it to be notified of the destruction of each object. ``_obj_create()`` should look like this:
389 402
390```c 403```c
404[...]
391 // First create a root element 405 // First create a root element
392 _root = efl_add(EFL_MODEL_ITEM_CLASS, NULL, 406 _root = efl_add(EFL_MODEL_ITEM_CLASS, NULL,
393 efl_name_set(efl_added, "Root")); 407 efl_name_set(efl_added, "Root"));
@@ -411,6 +425,7 @@ Use it to be notified of the destruction of each object. ``_obj_create()`` shoul
411 efl_wref_add(_child2, &_child2_ref); 425 efl_wref_add(_child2, &_child2_ref);
412 // Register a callback for DELETION events 426 // Register a callback for DELETION events
413 efl_event_callback_add(_child2, EFL_EVENT_DEL, _obj_destroy_cb, NULL); 427 efl_event_callback_add(_child2, EFL_EVENT_DEL, _obj_destroy_cb, NULL);
428[...]
414``` 429```
415 430
416The first parameter to ``efl_event_callback_add()`` is the object you want to track. The second one is the type of event you want to be notified of (``EFL_EVENT_DEL``). The third parameter is the callback you need to write (``_obj_destroy_cb``), and the fourth one is extra data you might want to pass to your callback (none, in this case). 431The first parameter to ``efl_event_callback_add()`` is the object you want to track. The second one is the type of event you want to be notified of (``EFL_EVENT_DEL``). The third parameter is the callback you need to write (``_obj_destroy_cb``), and the fourth one is extra data you might want to pass to your callback (none, in this case).
@@ -418,6 +433,7 @@ The first parameter to ``efl_event_callback_add()`` is the object you want to tr
418Write now the notification callback, right above ``_obj_create()``: 433Write now the notification callback, right above ``_obj_create()``:
419 434
420```c 435```c
436[...]
421// Gets called whenever an object is deleted 437// Gets called whenever an object is deleted
422static void 438static void
423_obj_destroy_cb(void *data EINA_UNUSED, const Efl_Event *event) 439_obj_destroy_cb(void *data EINA_UNUSED, const Efl_Event *event)
@@ -427,6 +443,7 @@ _obj_destroy_cb(void *data EINA_UNUSED, const Efl_Event *event)
427 printf("Object named \"%s\" is about to be deleted\n", efl_name_get(obj)); 443 printf("Object named \"%s\" is about to be deleted\n", efl_name_get(obj));
428 _status_print(); 444 _status_print();
429} 445}
446[...]
430``` 447```
431 448
432All callback methods in EFL are generic, in that they receive the custom data you passed when you registered the callback, and then an ``Efl_Event *`` with the details of the event that triggered the callback. 449All callback methods in EFL are generic, in that they receive the custom data you passed when you registered the callback, and then an ``Efl_Event *`` with the details of the event that triggered the callback.
@@ -606,4 +623,4 @@ At the end of this tutorial you have learned:
606: Part one of this tutorial 623: Part one of this tutorial
607 624
608[Setting up the Development Environment](/develop/setup/c/) 625[Setting up the Development Environment](/develop/setup/c/)
609: Read this before trying to develop with the EFL 626: Read this before trying to develop with the EFL \ No newline at end of file