Lely core libraries  2.2.5
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 (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 
46 void
48 {
49  if (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) {
55  atomic_thread_fence(memory_order_acquire);
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 
66 int
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 
76 struct 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 (!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 
105 void
106 io_handle_fini(struct io_handle *handle)
107 {
108  assert(handle);
109  assert(handle->vtab);
110 
111  if (handle->vtab->fini)
112  handle->vtab->fini(handle);
113 }
114 
115 void
116 io_handle_free(struct io_handle *handle)
117 {
118  if (handle) {
119 #ifndef LELY_NO_THREADS
120  mtx_destroy(&handle->mtx);
121 #endif
122 
123  free(handle);
124  }
125 }
126 
127 void
129 {
130  if (handle) {
131  io_handle_fini(handle);
132  io_handle_free(handle);
133  }
134 }
135 
136 #ifndef LELY_NO_THREADS
137 
138 void
139 io_handle_lock(struct io_handle *handle)
140 {
141  assert(handle);
142 
143  mtx_lock(&handle->mtx);
144 }
145 
146 void
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
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
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
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
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 Windows-specific I/O declarations.
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.
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.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
Definition: threads.h:109