Lely core libraries 1.9.2
handle.c
Go to the documentation of this file.
1
24#include "handle.h"
25#include "io.h"
26#include <lely/util/errnum.h>
27
28#include <assert.h>
29#include <stdlib.h>
30
33{
34 if (__likely(handle != IO_HANDLE_ERROR))
35#ifndef LELY_NO_ATOMICS
36 atomic_fetch_add_explicit(
37 &handle->ref, 1, memory_order_relaxed);
38#elif !defined(LELY_NO_THREADS) && defined(_WIN32)
39 InterlockedIncrementNoFence(&handle->ref);
40#else
41 handle->ref++;
42#endif
43 return handle;
44}
45
46void
48{
49 if (__unlikely(handle == IO_HANDLE_ERROR))
50 return;
51
52#ifndef LELY_NO_ATOMICS
53 if (atomic_fetch_sub_explicit(&handle->ref, 1, memory_order_release)
54 == 1) {
56#elif !defined(LELY_NO_THREADS) && defined(_WIN32)
57 if (!InterlockedDecrementRelease(&handle->ref)) {
58 MemoryBarrier();
59#else
60 if (handle->ref-- == 1) {
61#endif
62 io_handle_destroy(handle);
63 }
64}
65
66int
68{
69#ifndef LELY_NO_ATOMICS
70 return handle != IO_HANDLE_ERROR && atomic_load(&handle->ref) == 1;
71#else
72 return handle != IO_HANDLE_ERROR && handle->ref == 1;
73#endif
74}
75
76struct io_handle *
78{
79 assert(vtab);
80 assert(vtab->size >= sizeof(struct io_handle));
81
82 struct io_handle *handle = malloc(vtab->size);
83 if (__unlikely(!handle)) {
84 set_errc(errno2c(errno));
85 return NULL;
86 }
87
88 handle->vtab = vtab;
89#ifndef LELY_NO_ATOMICS
90 atomic_init(&handle->ref, 0);
91#else
92 handle->ref = 0;
93#endif
94 handle->fd = INVALID_HANDLE_VALUE;
95
96#ifndef LELY_NO_THREADS
97 mtx_init(&handle->mtx, mtx_plain);
98#endif
99
100 handle->flags = 0;
101
102 return handle;
103}
104
105void
107{
108 assert(handle);
109 assert(handle->vtab);
110
111 if (handle->vtab->fini)
112 handle->vtab->fini(handle);
113}
114
115void
117{
118 if (handle) {
119#ifndef LELY_NO_THREADS
120 mtx_destroy(&handle->mtx);
121#endif
122
123 free(handle);
124 }
125}
126
127void
129{
130 if (handle) {
131 io_handle_fini(handle);
132 io_handle_free(handle);
133 }
134}
135
136#ifndef LELY_NO_THREADS
137
138void
140{
141 assert(handle);
142
143 mtx_lock(&handle->mtx);
144}
145
146void
148{
149 assert(handle);
150
151 mtx_unlock(&handle->mtx);
152}
153
154#endif // !LELY_NO_THREADS
This header file is part of the utilities library; it contains the native and platform-independent er...
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
io_handle_t io_handle_acquire(io_handle_t handle)
Increments the reference count of an I/O device handle.
Definition: handle.c:32
void io_handle_fini(struct io_handle *handle)
Finalizes an I/O device handle by invoking its fini method, if available.
Definition: handle.c:106
int io_handle_unique(io_handle_t handle)
Returns 1 if there is only a single reference to the specified I/O device handle, and 0 otherwise.
Definition: handle.c:67
void io_handle_destroy(struct io_handle *handle)
Destroys an I/O device handle.
Definition: handle.c:128
void io_handle_free(struct io_handle *handle)
Frees an I/O device handle.
Definition: handle.c:116
struct io_handle * io_handle_alloc(const struct io_handle_vtab *vtab)
Allocates a new I/O device handle from a virtual table.
Definition: handle.c:77
void io_handle_unlock(struct io_handle *handle)
Unlocks a locked I/O device handle.
Definition: handle.c:147
void io_handle_release(io_handle_t handle)
Decrements the reference count of an I/O device handle.
Definition: handle.c:47
void io_handle_lock(struct io_handle *handle)
Locks an unlocked I/O device handle, so the flags (and other device-specific fields) can safely be ac...
Definition: handle.c:139
This is the internal header file of the I/O handle declarations.
#define IO_HANDLE_ERROR
The value of an invalid I/O device handle.
Definition: io.h:34
This is the internal header file of the I/O library.
@ memory_order_release
A store operation performs a release operation on the affected memory location.
Definition: stdatomic.h:160
@ memory_order_relaxed
No operation orders memory.
Definition: stdatomic.h:133
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
Definition: stdatomic.h:151
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
Definition: stdatomic.h:616
#define atomic_load(object)
Equivalent to #atomic_load_explicit(object, memory_order_seq_cst).
Definition: stdatomic.h:332
#define atomic_init(obj, value)
Initializes the atomic object at obj with the value value.
Definition: stdatomic.h:221
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
The virtual table of an I/O device handle.
Definition: handle.h:74
void(* fini)(struct io_handle *handle)
A pointer to the fini method.
Definition: handle.h:83
size_t size
The size (in bytes) of the handle struct.
Definition: handle.h:81
An I/O device handle.
Definition: handle.h:41
int fd
The native file descriptor.
Definition: handle.h:56
size_t ref
The reference count.
Definition: handle.h:50
int flags
The I/O device flags (any combination of IO_FLAG_NO_CLOSE and IO_FLAG_NONBLOCK).
Definition: handle.h:62
mtx_t mtx
The mutex protecting flags (and other device-specific fields).
Definition: handle.h:65
const struct io_handle_vtab * vtab
A pointer to the virtual table.
Definition: handle.h:43
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values:
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
Definition: threads.h:109
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.