Replace obsolete argument "sessiondir" with "workdir"
[src/app-framework-binder.git] / src / fdev.c
1 /*
2  * Copyright (C) 2018, 2019 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <errno.h>
22
23 #define FDEV_PROVIDER
24 #include "fdev.h"
25
26 struct fdev
27 {
28         int fd;
29         uint32_t events;
30         unsigned refcount;
31         struct fdev_itf *itf;
32         void *closure_itf;
33         void (*callback)(void*,uint32_t,struct fdev*);
34         void *closure_callback;
35 };
36
37 struct fdev *fdev_create(int fd)
38 {
39         struct fdev *fdev;
40
41         fdev = calloc(1, sizeof *fdev);
42         if (!fdev)
43                 errno = ENOMEM;
44         else {
45                 fdev->fd = fd;
46                 fdev->refcount = 3; /* set autoclose by default */
47         }
48         return fdev;
49 }
50
51 void fdev_set_itf(struct fdev *fdev, struct fdev_itf *itf, void *closure_itf)
52 {
53         fdev->itf = itf;
54         fdev->closure_itf = closure_itf;
55 }
56
57 void fdev_dispatch(struct fdev *fdev, uint32_t events)
58 {
59         if (fdev->callback)
60                 fdev->callback(fdev->closure_callback, events, fdev);
61 }
62
63 struct fdev *fdev_addref(struct fdev *fdev)
64 {
65         if (fdev)
66                 __atomic_add_fetch(&fdev->refcount, 2, __ATOMIC_RELAXED);
67         return fdev;
68 }
69
70 void fdev_unref(struct fdev *fdev)
71 {
72         if (fdev && __atomic_sub_fetch(&fdev->refcount, 2, __ATOMIC_RELAXED) <= 1) {
73                 if (fdev->itf) {
74                         fdev->itf->disable(fdev->closure_itf, fdev);
75                         if (fdev->itf->unref)
76                                 fdev->itf->unref(fdev->closure_itf);
77                 }
78                 if (fdev->refcount)
79                         close(fdev->fd);
80                 free(fdev);
81         }
82 }
83
84 int fdev_fd(const struct fdev *fdev)
85 {
86         return fdev->fd;
87 }
88
89 uint32_t fdev_events(const struct fdev *fdev)
90 {
91         return fdev->events;
92 }
93
94 int fdev_autoclose(const struct fdev *fdev)
95 {
96         return 1 & fdev->refcount;
97 }
98
99 static inline int is_active(struct fdev *fdev)
100 {
101         return !!fdev->callback;
102 }
103
104 static inline void update_activity(struct fdev *fdev, int old_active)
105 {
106         if (is_active(fdev)) {
107                 if (!old_active)
108                         fdev->itf->enable(fdev->closure_itf, fdev);
109         } else {
110                 if (old_active)
111                         fdev->itf->disable(fdev->closure_itf, fdev);
112         }
113 }
114
115 void fdev_set_callback(struct fdev *fdev, void (*callback)(void*,uint32_t,struct fdev*), void *closure)
116 {
117         int oa;
118
119         oa = is_active(fdev);
120         fdev->callback = callback;
121         fdev->closure_callback = closure;
122         update_activity(fdev, oa);
123 }
124
125 void fdev_set_events(struct fdev *fdev, uint32_t events)
126 {
127         if (events != fdev->events) {
128                 fdev->events = events;
129                 if (is_active(fdev))
130                         fdev->itf->update(fdev->closure_itf, fdev);
131         }
132 }
133
134 void fdev_set_autoclose(struct fdev *fdev, int autoclose)
135 {
136         if (autoclose)
137                 fdev->refcount |= (unsigned)1;
138         else
139                 fdev->refcount &= ~(unsigned)1;
140 }
141