docs: Move GRcBox/GArcBox and refcounting docs to Markdown

Helps: #3037
This commit is contained in:
Matthias Clasen 2023-10-09 23:07:59 +01:00 committed by Philip Withnall
parent 6107f50cc7
commit c3713e1b67
6 changed files with 166 additions and 278 deletions

View File

@ -40,6 +40,7 @@ show_class_hierarchy = true
urlmap_file = "urlmap.js"
# The same order will be used when generating the index
content_files = [
"reference-counting.md",
]
content_images = [
"Sorted_binary_tree_breadth-first_traversal.svg",

View File

@ -152,6 +152,7 @@ endif
# gi-docgen version
expand_content_files = [
'reference-counting.md',
]
glib_gir = meson.current_source_dir() / 'GLib-2.0.gir'

View File

@ -0,0 +1,164 @@
Title: Reference Counting
## Reference counting types
Reference counting is a garbage collection mechanism that is based on
assigning a counter to a data type, or any memory area; the counter is
increased whenever a new reference to that data type is acquired, and
decreased whenever the reference is released. Once the last reference is
released, the resources associated to that data type are freed.
GLib uses reference counting in many of its data types, and provides the
`grefcount` and `gatomicrefcount` types to implement safe and atomic
reference counting semantics in new data types.
It is important to note that `grefcount` and `gatomicrefcount` should be
considered completely opaque types; you should always use the provided API
to increase and decrease the counters, and you should never check their
content directly, or compare their content with other values.
## Reference counted data
A "reference counted box", or "RcBox", is an opaque wrapper data type that
is guaranteed to be as big as the size of a given data type, and which
augments the given data type with reference counting semantics for its
memory management.
RcBox is useful if you have a plain old data type, like a structure
typically placed on the stack, and you wish to provide additional API to use
it on the heap; or if you want to implement a new type to be passed around
by reference without necessarily implementing copy/free semantics or your
own reference counting.
The typical use is:
```c
typedef struct {
char *name;
char *address;
char *city;
char *state;
int age;
} Person;
Person *
person_new (void)
{
return g_rc_box_new0 (Person);
}
```
Every time you wish to acquire a reference on the memory, you should call
`g_rc_box_acquire()`; similarly, when you wish to release a reference you
should call `g_rc_box_release()`:
```c
// Add a Person to the Database; the Database acquires ownership
// of the Person instance
void
add_person_to_database (Database *db, Person *p)
{
db->persons = g_list_prepend (db->persons, g_rc_box_acquire (p));
}
// Removes a Person from the Database; the reference acquired by
// add_person_to_database() is released here
void
remove_person_from_database (Database *db, Person *p)
{
db->persons = g_list_remove (db->persons, p);
g_rc_box_release (p);
}
```
If you have additional memory allocated inside the structure, you can use
`g_rc_box_release_full()`, which takes a function pointer, which will be
called if the reference released was the last:
```c
void
person_clear (Person *p)
{
g_free (p->name);
g_free (p->address);
g_free (p->city);
g_free (p->state);
}
void
remove_person_from_database (Database *db, Person *p)
{
db->persons = g_list_remove (db->persons, p);
g_rc_box_release_full (p, (GDestroyNotify) person_clear);
}
```
If you wish to transfer the ownership of a reference counted data
type without increasing the reference count, you can use `g_steal_pointer()`:
```c
Person *p = g_rc_box_new (Person);
// fill_person_details() is defined elsewhere
fill_person_details (p);
// add_person_to_database_no_ref() is defined elsewhere; it adds
// a Person to the Database without taking a reference
add_person_to_database_no_ref (db, g_steal_pointer (&p));
```
## Thread safety
The reference counting operations on data allocated using
`g_rc_box_alloc()`, `g_rc_box_new()`, and `g_rc_box_dup()` are not thread
safe; it is your code's responsibility to ensure that references are
acquired are released on the same thread.
If you need thread safe reference counting, you should use the
`g_atomic_rc_*` API:
| Operation | Atomic equivalent |
|---------------------------|----------------------------------|
| `g_rc_box_alloc()` | `g_atomic_rc_box_alloc()` |
| `g_rc_box_new()` | `g_atomic_rc_box_new()` |
| `g_rc_box_dup()` | `g_atomic_rc_box_dup()` |
| `g_rc_box_acquire()` | `g_atomic_rc_box_acquire()` |
| `g_rc_box_release()` | `g_atomic_rc_box_release()` |
| `g_rc_box_release_full()` | `g_atomic_rc_box_release_full()` |
The reference counting operations on data allocated using
`g_atomic_rc_box_alloc()`, `g_atomic_rc_box_new()`, and
`g_atomic_rc_box_dup()` are guaranteed to be atomic, and thus can be safely
be performed by different threads. It is important to note that only the
reference acquisition and release are atomic; changes to the content of the
data are your responsibility.
It is a programmer error to mix the atomic and non-atomic reference counting
operations.
## Automatic pointer clean up
If you want to add `g_autoptr()` support to your plain old data type through
reference counting, you can use the `G_DEFINE_AUTOPTR_CLEANUP_FUNC()` and
`g_rc_box_release()`:
```c
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_rc_box_release)
```
If you need to clear the contents of the data, you will need to use an
ancillary function that calls `g_rc_box_release_full()`:
```c
static void
my_data_struct_release (MyDataStruct *data)
{
// my_data_struct_clear() is defined elsewhere
g_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release)
```
The `g_rc_box*` and `g_atomic_rc_box*` APIs were introduced in GLib 2.58.

View File

@ -35,131 +35,6 @@
#define G_ARC_BOX(p) (GArcBox *) (((char *) (p)) - G_ARC_BOX_SIZE)
/**
* SECTION:arcbox
* @Title: Atomically reference counted data
* @Short_description: Allocated memory with atomic reference counting semantics
*
* An "atomically reference counted box", or "ArcBox", is an opaque wrapper
* data type that is guaranteed to be as big as the size of a given data type,
* and which augments the given data type with thread safe reference counting
* semantics for its memory management.
*
* ArcBox is useful if you have a plain old data type, like a structure
* typically placed on the stack, and you wish to provide additional API
* to use it on the heap; or if you want to implement a new type to be
* passed around by reference without necessarily implementing copy/free
* semantics or your own reference counting.
*
* The typical use is:
*
* |[<!-- language="C" -->
* typedef struct {
* char *name;
* char *address;
* char *city;
* char *state;
* int age;
* } Person;
*
* Person *
* person_new (void)
* {
* return g_atomic_rc_box_new0 (Person);
* }
* ]|
*
* Every time you wish to acquire a reference on the memory, you should
* call g_atomic_rc_box_acquire(); similarly, when you wish to release a reference
* you should call g_atomic_rc_box_release():
*
* |[<!-- language="C" -->
* // Add a Person to the Database; the Database acquires ownership
* // of the Person instance
* void
* add_person_to_database (Database *db, Person *p)
* {
* db->persons = g_list_prepend (db->persons, g_atomic_rc_box_acquire (p));
* }
*
* // Removes a Person from the Database; the reference acquired by
* // add_person_to_database() is released here
* void
* remove_person_from_database (Database *db, Person *p)
* {
* db->persons = g_list_remove (db->persons, p);
* g_atomic_rc_box_release (p);
* }
* ]|
*
* If you have additional memory allocated inside the structure, you can
* use g_atomic_rc_box_release_full(), which takes a function pointer, which
* will be called if the reference released was the last:
*
* |[<!-- language="C" -->
* void
* person_clear (Person *p)
* {
* g_free (p->name);
* g_free (p->address);
* g_free (p->city);
* g_free (p->state);
* }
*
* void
* remove_person_from_database (Database *db, Person *p)
* {
* db->persons = g_list_remove (db->persons, p);
* g_atomic_rc_box_release_full (p, (GDestroyNotify) person_clear);
* }
* ]|
*
* If you wish to transfer the ownership of a reference counted data
* type without increasing the reference count, you can use g_steal_pointer():
*
* |[<!-- language="C" -->
* Person *p = g_atomic_rc_box_new (Person);
*
* fill_person_details (p);
*
* add_person_to_database (db, g_steal_pointer (&p));
* ]|
*
* ## Thread safety
*
* The reference counting operations on data allocated using g_atomic_rc_box_alloc(),
* g_atomic_rc_box_new(), and g_atomic_rc_box_dup() are guaranteed to be atomic, and thus
* can be safely be performed by different threads. It is important to note that
* only the reference acquisition and release are atomic; changes to the content
* of the data are your responsibility.
*
* ## Automatic pointer clean up
*
* If you want to add g_autoptr() support to your plain old data type through
* reference counting, you can use the G_DEFINE_AUTOPTR_CLEANUP_FUNC() and
* g_atomic_rc_box_release():
*
* |[<!-- language="C" -->
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_atomic_rc_box_release)
* ]|
*
* If you need to clear the contents of the data, you will need to use an
* ancillary function that calls g_rc_box_release_full():
*
* |[<!-- language="C" -->
* static void
* my_data_struct_release (MyDataStruct *data)
* {
* // my_data_struct_clear() is defined elsewhere
* g_atomic_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear);
* }
*
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release)
* ]|
*
* Since: 2.58
*/
/**
* g_atomic_rc_box_alloc:
* @block_size: the size of the allocation, must be greater than 0

View File

@ -34,136 +34,6 @@
#include <string.h>
/**
* SECTION:rcbox
* @Title: Reference counted data
* @Short_description: Allocated memory with reference counting semantics
*
* A "reference counted box", or "RcBox", is an opaque wrapper data type
* that is guaranteed to be as big as the size of a given data type, and
* which augments the given data type with reference counting semantics
* for its memory management.
*
* RcBox is useful if you have a plain old data type, like a structure
* typically placed on the stack, and you wish to provide additional API
* to use it on the heap; or if you want to implement a new type to be
* passed around by reference without necessarily implementing copy/free
* semantics or your own reference counting.
*
* The typical use is:
*
* |[<!-- language="C" -->
* typedef struct {
* char *name;
* char *address;
* char *city;
* char *state;
* int age;
* } Person;
*
* Person *
* person_new (void)
* {
* return g_rc_box_new0 (Person);
* }
* ]|
*
* Every time you wish to acquire a reference on the memory, you should
* call g_rc_box_acquire(); similarly, when you wish to release a reference
* you should call g_rc_box_release():
*
* |[<!-- language="C" -->
* // Add a Person to the Database; the Database acquires ownership
* // of the Person instance
* void
* add_person_to_database (Database *db, Person *p)
* {
* db->persons = g_list_prepend (db->persons, g_rc_box_acquire (p));
* }
*
* // Removes a Person from the Database; the reference acquired by
* // add_person_to_database() is released here
* void
* remove_person_from_database (Database *db, Person *p)
* {
* db->persons = g_list_remove (db->persons, p);
* g_rc_box_release (p);
* }
* ]|
*
* If you have additional memory allocated inside the structure, you can
* use g_rc_box_release_full(), which takes a function pointer, which
* will be called if the reference released was the last:
*
* |[<!-- language="C" -->
* void
* person_clear (Person *p)
* {
* g_free (p->name);
* g_free (p->address);
* g_free (p->city);
* g_free (p->state);
* }
*
* void
* remove_person_from_database (Database *db, Person *p)
* {
* db->persons = g_list_remove (db->persons, p);
* g_rc_box_release_full (p, (GDestroyNotify) person_clear);
* }
* ]|
*
* If you wish to transfer the ownership of a reference counted data
* type without increasing the reference count, you can use g_steal_pointer():
*
* |[<!-- language="C" -->
* Person *p = g_rc_box_new (Person);
*
* // fill_person_details() is defined elsewhere
* fill_person_details (p);
*
* // add_person_to_database_no_ref() is defined elsewhere; it adds
* // a Person to the Database without taking a reference
* add_person_to_database_no_ref (db, g_steal_pointer (&p));
* ]|
*
* ## Thread safety
*
* The reference counting operations on data allocated using g_rc_box_alloc(),
* g_rc_box_new(), and g_rc_box_dup() are not thread safe; it is your code's
* responsibility to ensure that references are acquired are released on the
* same thread.
*
* If you need thread safe reference counting, see the [atomic reference counted
* data][arcbox] API.
*
* ## Automatic pointer clean up
*
* If you want to add g_autoptr() support to your plain old data type through
* reference counting, you can use the G_DEFINE_AUTOPTR_CLEANUP_FUNC() and
* g_rc_box_release():
*
* |[<!-- language="C" -->
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_rc_box_release)
* ]|
*
* If you need to clear the contents of the data, you will need to use an
* ancillary function that calls g_rc_box_release_full():
*
* |[<!-- language="C" -->
* static void
* my_data_struct_release (MyDataStruct *data)
* {
* // my_data_struct_clear() is defined elsewhere
* g_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear);
* }
*
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release)
* ]|
*
* Since: 2.58
*/
/* We use the same alignment as GTypeInstance and GNU libc's malloc */
#define ALIGN_STRUCT(offset) ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT)

View File

@ -18,29 +18,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:refcount
* @Title: Reference counting
* @Short_description: Reference counting types and functions
*
* Reference counting is a garbage collection mechanism that is based on
* assigning a counter to a data type, or any memory area; the counter is
* increased whenever a new reference to that data type is acquired, and
* decreased whenever the reference is released. Once the last reference
* is released, the resources associated to that data type are freed.
*
* GLib uses reference counting in many of its data types, and provides
* the #grefcount and #gatomicrefcount types to implement safe and atomic
* reference counting semantics in new data types.
*
* It is important to note that #grefcount and #gatomicrefcount should be
* considered completely opaque types; you should always use the provided
* API to increase and decrease the counters, and you should never check
* their content directly, or compare their content with other values.
*
* Since: 2.58
*/
#include "config.h"
#include "grefcount.h"