diff options
author | Guillaume Friloux <guillaume.friloux@gmail.com> | 2013-12-16 13:38:00 +0100 |
---|---|---|
committer | Guillaume Friloux <guillaume.friloux@gmail.com> | 2013-12-16 13:38:00 +0100 |
commit | 57f2fc4c766e65d2d7a601ab52c9b761957ba8db (patch) | |
tree | 032677066b6b9de8add32b8b412f17723116e1cd /src | |
parent | c8787af0cf251521e63bbee5717fe0d11c657f7d (diff) |
Adding libspy.
It needs to be used by smman as this will consume less cpu cycles than
managing inotify events. When having a lot of logs, inotify events gets
too annoying, thus the fact that we miss some of them.
With libspy, files will be polled periodically, no matter the activity
on them.
Diffstat (limited to 'src')
-rw-r--r-- | src/include/Spy.h | 25 | ||||
-rw-r--r-- | src/lib/Makefile.mk | 12 | ||||
-rw-r--r-- | src/lib/spy/spy_file.c | 208 | ||||
-rw-r--r-- | src/lib/spy/spy_main.c | 157 | ||||
-rw-r--r-- | src/lib/spy/spy_private.h | 44 |
5 files changed, 445 insertions, 1 deletions
diff --git a/src/include/Spy.h b/src/include/Spy.h new file mode 100644 index 0000000..cc13da7 --- /dev/null +++ b/src/include/Spy.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef SPY_H | ||
2 | #define SPY_H | ||
3 | #include <Eina.h> | ||
4 | #include <Ecore.h> | ||
5 | #include <Eio.h> | ||
6 | |||
7 | extern int SPY_EVENT_LINE; | ||
8 | |||
9 | typedef struct _Spy Spy; | ||
10 | typedef struct _Spy_File Spy_File; | ||
11 | typedef struct _Spy_Line Spy_Line; | ||
12 | |||
13 | int spy_init(void); | ||
14 | int spy_shutdown(void); | ||
15 | |||
16 | Spy * spy_new(void); | ||
17 | void spy_free(Spy *spy); | ||
18 | |||
19 | Spy_File *spy_file_new(Spy *spy, const char *file); | ||
20 | const char * spy_line_get(Spy_Line *sl); | ||
21 | const char *spy_file_name_get(Spy_File *sf); | ||
22 | void spy_file_data_set(Spy_File *sf, const void *data); | ||
23 | const void *spy_file_data_get(Spy_File *sf); | ||
24 | |||
25 | #endif | ||
diff --git a/src/lib/Makefile.mk b/src/lib/Makefile.mk index a4e2945..88771bb 100644 --- a/src/lib/Makefile.mk +++ b/src/lib/Makefile.mk | |||
@@ -1,10 +1,20 @@ | |||
1 | MAINTAINERCLEANFILES += src/lib/*.gc{no,da} | 1 | MAINTAINERCLEANFILES += src/lib/*.gc{no,da} |
2 | 2 | ||
3 | noinst_LTLIBRARIES = \ | 3 | noinst_LTLIBRARIES = \ |
4 | src/lib/libconf.la | 4 | src/lib/libconf.la \ |
5 | src/lib/libspy.la | ||
5 | 6 | ||
6 | src_lib_libconf_la_SOURCES = \ | 7 | src_lib_libconf_la_SOURCES = \ |
7 | src/lib/conf.c \ | 8 | src/lib/conf.c \ |
8 | src/include/Conf.h | 9 | src/include/Conf.h |
9 | src_lib_libconf_la_CFLAGS = $(LIBS_CFLAGS) $(EXTRA_CPPFLAGS) | 10 | src_lib_libconf_la_CFLAGS = $(LIBS_CFLAGS) $(EXTRA_CPPFLAGS) |
10 | src_lib_libconf_la_LDFLAGS = $(LIBS_CFLAGS) | 11 | src_lib_libconf_la_LDFLAGS = $(LIBS_CFLAGS) |
12 | |||
13 | src_lib_libspy_la_SOURCES = \ | ||
14 | src/lib/spy/spy_file.c \ | ||
15 | src/lib/spy/spy_main.c \ | ||
16 | src/lib/spy/spy_private.h \ | ||
17 | src/include/Spy.h | ||
18 | src_lib_libspy_la_CFLAGS = $(LIBS_CFLAGS) $(EXTRA_CPPFLAGS) | ||
19 | src_lib_libspy_la_LDFLAGS = $(LIBS_CFLAGS) | ||
20 | |||
diff --git a/src/lib/spy/spy_file.c b/src/lib/spy/spy_file.c new file mode 100644 index 0000000..397862e --- /dev/null +++ b/src/lib/spy/spy_file.c | |||
@@ -0,0 +1,208 @@ | |||
1 | #include "spy_private.h" | ||
2 | |||
3 | static void | ||
4 | _spy_file_job(void *data) | ||
5 | { | ||
6 | spy_file_poll(data); | ||
7 | } | ||
8 | |||
9 | void | ||
10 | _spy_file_line_free(void *d1, | ||
11 | void *d2 EINA_UNUSED) | ||
12 | { | ||
13 | Spy_Line *sl = d1; | ||
14 | |||
15 | free((char *)sl->line); | ||
16 | free(sl); | ||
17 | } | ||
18 | |||
19 | void | ||
20 | _spy_file_line_extract(Spy_File *sf) | ||
21 | { | ||
22 | const char *s, | ||
23 | *p, | ||
24 | *p1; | ||
25 | size_t rm = 0; | ||
26 | Spy_Line *sl; | ||
27 | |||
28 | s = eina_strbuf_string_get(sf->read.buf); | ||
29 | p = s; | ||
30 | |||
31 | while ((p1=strchr(p, '\n'))) | ||
32 | { | ||
33 | size_t l = p1 - p; | ||
34 | char *line; | ||
35 | |||
36 | rm += l; | ||
37 | |||
38 | if (!l) | ||
39 | goto end; | ||
40 | |||
41 | line = strndup(p, l); | ||
42 | |||
43 | DBG("Line = %s len=%zd", line, l); | ||
44 | sl = calloc(1, sizeof(Spy_Line)); | ||
45 | if (!sl) | ||
46 | { | ||
47 | ERR("Failed to allocate Spy_Line"); | ||
48 | free(line); | ||
49 | } | ||
50 | |||
51 | sl->sf = sf; | ||
52 | sl->line = line; | ||
53 | ecore_event_add(SPY_EVENT_LINE, sl, _spy_file_line_free, sl); | ||
54 | end: | ||
55 | p = p1 + 1; | ||
56 | } | ||
57 | |||
58 | eina_strbuf_remove(sf->read.buf, 0, rm); | ||
59 | } | ||
60 | |||
61 | void | ||
62 | _spy_file_cb(void *data, | ||
63 | Ecore_Thread *thread EINA_UNUSED) | ||
64 | { | ||
65 | Spy_File *sf; | ||
66 | size_t nbr = 0, | ||
67 | toread = 0, | ||
68 | left = 0; | ||
69 | char buf[512]; | ||
70 | |||
71 | sf = data; | ||
72 | DBG("sf[%p]", sf); | ||
73 | |||
74 | sf->read.fd = fopen(sf->name, "r"); | ||
75 | if (!sf->read.fd) | ||
76 | { | ||
77 | ERR("Failed to open %s : %s", sf->name, strerror(errno)); | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | fseeko(sf->read.fd, sf->read.offset, SEEK_SET); | ||
82 | left = sf->read.length; | ||
83 | |||
84 | while (nbr != (size_t)sf->read.length) | ||
85 | { | ||
86 | toread = (left < 512) ? left : 512; | ||
87 | |||
88 | if (fread(buf, toread, 1, sf->read.fd) != 1) | ||
89 | { | ||
90 | ERR("Error while reading file %s : %s", | ||
91 | sf->name, strerror(errno)); | ||
92 | fclose(sf->read.fd); | ||
93 | return; | ||
94 | } | ||
95 | eina_strbuf_append_length(sf->read.buf, buf, toread); | ||
96 | _spy_file_line_extract(sf); | ||
97 | nbr += toread; | ||
98 | } | ||
99 | fclose(sf->read.fd); | ||
100 | sf->read.fd = NULL; | ||
101 | } | ||
102 | |||
103 | void | ||
104 | _spy_file_end_cb(void *data, | ||
105 | Ecore_Thread *thread EINA_UNUSED) | ||
106 | { | ||
107 | Spy_File *sf; | ||
108 | |||
109 | sf = data; | ||
110 | DBG("sf[%p]", sf); | ||
111 | |||
112 | ecore_timer_thaw(sf->poll.timer); | ||
113 | ecore_timer_reset(sf->poll.timer); | ||
114 | |||
115 | ecore_job_add(_spy_file_job, sf); | ||
116 | } | ||
117 | |||
118 | void | ||
119 | _spy_file_cancel_cb(void *data EINA_UNUSED, | ||
120 | Ecore_Thread *thread EINA_UNUSED) | ||
121 | {} | ||
122 | |||
123 | Eina_Bool | ||
124 | spy_file_poll(void *data) | ||
125 | { | ||
126 | Spy_File *sf; | ||
127 | off_t size, | ||
128 | toread; | ||
129 | struct stat st; | ||
130 | Ecore_Thread *et; | ||
131 | |||
132 | sf = data; | ||
133 | DBG("spy_file[%p] file[%s]", sf, sf->name); | ||
134 | |||
135 | /* We should have different actions made depending on error type. */ | ||
136 | if (stat(sf->name, &st)) | ||
137 | { | ||
138 | ERR("Failed to get size of %s : %s", sf->name, strerror(errno)); | ||
139 | return EINA_TRUE; | ||
140 | } | ||
141 | |||
142 | size = st.st_size; | ||
143 | DBG("size=%zu", size); | ||
144 | if (sf->poll.size == size) | ||
145 | return EINA_TRUE; | ||
146 | |||
147 | /* File has been trunc! */ | ||
148 | if (sf->poll.size > size) | ||
149 | { | ||
150 | DBG("spy_file[%p] File trunc!", sf); | ||
151 | sf->poll.size = 0; | ||
152 | |||
153 | if (!size) | ||
154 | return EINA_TRUE; | ||
155 | } | ||
156 | |||
157 | /* We have data to read! */ | ||
158 | DBG("spy_file[%p] File activity!", sf); | ||
159 | |||
160 | toread = size - sf->poll.size; | ||
161 | |||
162 | DBG("spy_file[%p] len_old=%zu len_new=%zu toread=%zu", | ||
163 | sf, sf->poll.size, size, toread); | ||
164 | |||
165 | sf->read.offset = sf->poll.size; | ||
166 | sf->read.length = toread; | ||
167 | |||
168 | |||
169 | et = ecore_thread_run(_spy_file_cb, | ||
170 | _spy_file_end_cb, | ||
171 | _spy_file_cancel_cb, | ||
172 | sf); | ||
173 | if (!et) | ||
174 | { | ||
175 | ERR("Failed to create reading thread"); | ||
176 | return EINA_TRUE; | ||
177 | } | ||
178 | |||
179 | ecore_timer_freeze(sf->poll.timer); | ||
180 | sf->poll.size = size; | ||
181 | return EINA_TRUE; | ||
182 | } | ||
183 | |||
184 | const char * | ||
185 | spy_line_get(Spy_Line *sl) | ||
186 | { | ||
187 | return sl->line; | ||
188 | } | ||
189 | |||
190 | |||
191 | const char * | ||
192 | spy_file_name_get(Spy_File *sf) | ||
193 | { | ||
194 | return sf->name; | ||
195 | } | ||
196 | |||
197 | void | ||
198 | spy_file_data_set(Spy_File *sf, | ||
199 | const void *data) | ||
200 | { | ||
201 | sf->data = (const void *)data; | ||
202 | } | ||
203 | |||
204 | const void * | ||
205 | spy_file_data_get(Spy_File *sf) | ||
206 | { | ||
207 | return sf->data; | ||
208 | } | ||
diff --git a/src/lib/spy/spy_main.c b/src/lib/spy/spy_main.c new file mode 100644 index 0000000..8084050 --- /dev/null +++ b/src/lib/spy/spy_main.c | |||
@@ -0,0 +1,157 @@ | |||
1 | #include "spy_private.h" | ||
2 | #include <sys/stat.h> | ||
3 | #include <fcntl.h> | ||
4 | #include <unistd.h> | ||
5 | |||
6 | static int _spy_init_count = 0; | ||
7 | int _spy_log_dom_global = -1; | ||
8 | |||
9 | int SPY_EVENT_LINE = 0; | ||
10 | |||
11 | Spy * | ||
12 | spy_new(void) | ||
13 | { | ||
14 | Spy *spy; | ||
15 | |||
16 | spy = calloc(1, sizeof(Spy)); | ||
17 | DBG("spy[%p]", spy); | ||
18 | return spy; | ||
19 | } | ||
20 | |||
21 | void | ||
22 | spy_free(Spy *spy) | ||
23 | { | ||
24 | Eina_Inlist *l; | ||
25 | Spy_File *sf; | ||
26 | EINA_SAFETY_ON_NULL_RETURN(spy); | ||
27 | |||
28 | EINA_INLIST_FOREACH_SAFE(spy->files, l, sf) | ||
29 | { | ||
30 | free((char *)sf->name); | ||
31 | ecore_timer_del(sf->poll.timer); | ||
32 | eina_strbuf_free(sf->read.buf); | ||
33 | } | ||
34 | free(spy); | ||
35 | } | ||
36 | |||
37 | Spy_File * | ||
38 | spy_file_new(Spy *spy, const char *file) | ||
39 | { | ||
40 | Spy_File *sf; | ||
41 | struct stat st; | ||
42 | |||
43 | DBG("spy[%p] file[%s]", spy, file); | ||
44 | |||
45 | if (access(file, R_OK)) | ||
46 | { | ||
47 | ERR("Failed to access %s : %s", file, strerror(errno)); | ||
48 | return EINA_FALSE; | ||
49 | } | ||
50 | |||
51 | sf = calloc(1, sizeof(Spy_File)); | ||
52 | if (!sf) | ||
53 | { | ||
54 | ERR("Failed to allocate Spy_File structure"); | ||
55 | return EINA_FALSE; | ||
56 | } | ||
57 | |||
58 | sf->name = (const char *)strdup(file); | ||
59 | if (!sf->name) | ||
60 | { | ||
61 | ERR("Failed to dupe string \"%s\"", file); | ||
62 | goto free_sf; | ||
63 | } | ||
64 | |||
65 | if (stat(file, &st)) | ||
66 | { | ||
67 | ERR("Failed to get size of %s : %s", file, strerror(errno)); | ||
68 | goto free_name; | ||
69 | } | ||
70 | |||
71 | sf->read.buf = eina_strbuf_new(); | ||
72 | if (!sf->read.buf) | ||
73 | { | ||
74 | ERR("Failed to create stringbuffer"); | ||
75 | goto free_name; | ||
76 | } | ||
77 | |||
78 | sf->poll.size = st.st_size; | ||
79 | sf->poll.timer = ecore_timer_add(5.0, spy_file_poll, sf); | ||
80 | |||
81 | spy->files = eina_inlist_append(spy->files, EINA_INLIST_GET(sf)); | ||
82 | DBG("spy_file[%p] size[%zd]", sf, st.st_size); | ||
83 | return sf; | ||
84 | |||
85 | free_name: | ||
86 | free((char *)sf->name); | ||
87 | free_sf: | ||
88 | free(sf); | ||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | |||
93 | int | ||
94 | spy_init(void) | ||
95 | { | ||
96 | if (++_spy_init_count != 1) | ||
97 | return _spy_init_count; | ||
98 | |||
99 | if (!eina_init()) | ||
100 | { | ||
101 | fprintf(stderr, "Spy can not initialize Eina\n"); | ||
102 | return --_spy_init_count; | ||
103 | } | ||
104 | |||
105 | _spy_log_dom_global = eina_log_domain_register("spy", EINA_COLOR_RED); | ||
106 | if (_spy_log_dom_global < 0) | ||
107 | { | ||
108 | EINA_LOG_ERR("Spy can not create a general log domain"); | ||
109 | goto shutdown_eina; | ||
110 | } | ||
111 | |||
112 | if (!ecore_init()) | ||
113 | { | ||
114 | ERR("Can not initialize Ecore"); | ||
115 | goto unregister_log_domain; | ||
116 | } | ||
117 | |||
118 | if (!eio_init()) | ||
119 | { | ||
120 | ERR("Can not initialize Eio"); | ||
121 | goto shutdown_ecore; | ||
122 | } | ||
123 | |||
124 | SPY_EVENT_LINE = ecore_event_type_new(); | ||
125 | |||
126 | return _spy_init_count; | ||
127 | |||
128 | shutdown_ecore: | ||
129 | ecore_shutdown(); | ||
130 | unregister_log_domain: | ||
131 | eina_log_domain_unregister(_spy_log_dom_global); | ||
132 | _spy_log_dom_global = -1; | ||
133 | shutdown_eina: | ||
134 | eina_shutdown(); | ||
135 | return --_spy_init_count; | ||
136 | } | ||
137 | |||
138 | |||
139 | int | ||
140 | spy_shutdown(void) | ||
141 | { | ||
142 | if (_spy_init_count <= 0) | ||
143 | { | ||
144 | fprintf(stderr, "Spy init count not greater than 0 in shutdown."); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | if (--_spy_init_count != 0) | ||
149 | return _spy_init_count; | ||
150 | |||
151 | eio_shutdown(); | ||
152 | ecore_shutdown(); | ||
153 | eina_log_domain_unregister(_spy_log_dom_global); | ||
154 | _spy_log_dom_global = -1; | ||
155 | eina_shutdown(); | ||
156 | return _spy_init_count; | ||
157 | } | ||
diff --git a/src/lib/spy/spy_private.h b/src/lib/spy/spy_private.h new file mode 100644 index 0000000..287ea44 --- /dev/null +++ b/src/lib/spy/spy_private.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #include <Spy.h> | ||
2 | |||
3 | extern int _spy_log_dom_global; | ||
4 | |||
5 | #define ERR(...) EINA_LOG_DOM_ERR(_spy_log_dom_global, __VA_ARGS__) | ||
6 | #define DBG(...) EINA_LOG_DOM_DBG(_spy_log_dom_global, __VA_ARGS__) | ||
7 | #define NFO(...) EINA_LOG_DOM_INFO(_spy_log_dom_global, __VA_ARGS__) | ||
8 | #define WRN(...) EINA_LOG_DOM_WARN(_spy_log_dom_global, __VA_ARGS__) | ||
9 | #define CRI(...) EINA_LOG_DOM_CRIT(_spy_log_dom_global, __VA_ARGS__) | ||
10 | |||
11 | struct _Spy | ||
12 | { | ||
13 | Eina_Inlist *files; | ||
14 | }; | ||
15 | |||
16 | |||
17 | struct _Spy_File | ||
18 | { | ||
19 | EINA_INLIST; | ||
20 | const char *name; | ||
21 | const void *data; | ||
22 | |||
23 | struct | ||
24 | { | ||
25 | Ecore_Timer *timer; | ||
26 | off_t size; | ||
27 | } poll; | ||
28 | |||
29 | struct | ||
30 | { | ||
31 | FILE *fd; | ||
32 | off_t offset, | ||
33 | length; | ||
34 | Eina_Strbuf *buf; | ||
35 | } read; | ||
36 | }; | ||
37 | |||
38 | struct _Spy_Line | ||
39 | { | ||
40 | Spy_File *sf; | ||
41 | const char *line; | ||
42 | }; | ||
43 | |||
44 | Eina_Bool spy_file_poll(void *data); | ||