aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore/ecore_pipe.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/ecore/src/lib/ecore/ecore_pipe.c682
1 files changed, 682 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore/ecore_pipe.c b/libraries/ecore/src/lib/ecore/ecore_pipe.c
new file mode 100644
index 0000000..0ab7dd0
--- /dev/null
+++ b/libraries/ecore/src/lib/ecore/ecore_pipe.c
@@ -0,0 +1,682 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <errno.h>
8#include <math.h>
9
10#ifdef HAVE_ISFINITE
11# define ECORE_FINITE(t) isfinite(t)
12#else
13# ifdef _MSC_VER
14# define ECORE_FINITE(t) _finite(t)
15# else
16# define ECORE_FINITE(t) finite(t)
17# endif
18#endif
19
20#define FIX_HZ 1
21
22#ifdef FIX_HZ
23# ifndef _MSC_VER
24# include <sys/param.h>
25# endif
26# ifndef HZ
27# define HZ 100
28# endif
29#endif
30
31#ifdef HAVE_EVIL
32# include <Evil.h>
33#endif
34
35#ifdef HAVE_ESCAPE
36# include <Escape.h>
37#endif
38
39#include "Ecore.h"
40#include "ecore_private.h"
41
42#ifdef _WIN32
43# define FMT_SSIZE_T "%Id"
44#else
45# define FMT_SSIZE_T "%zd"
46#endif
47
48/* How of then we should retry to write to the pipe */
49#define ECORE_PIPE_WRITE_RETRY 6
50
51/*
52 * On Windows, pipe() is implemented with sockets.
53 * Contrary to Linux, Windows uses different functions
54 * for sockets and fd's: write() is for fd's and send
55 * is for sockets. So I need to put some win32 code
56 * here. I can't think of a solution where the win32
57 * code is in Evil and not here.
58 */
59
60#ifdef _WIN32
61
62# include <winsock2.h>
63
64# define pipe_write(fd, buffer, size) send((fd), (char *)(buffer), size, 0)
65# define pipe_read(fd, buffer, size) recv((fd), (char *)(buffer), size, 0)
66# define pipe_close(fd) closesocket(fd)
67# define PIPE_FD_INVALID INVALID_SOCKET
68# define PIPE_FD_ERROR SOCKET_ERROR
69
70#else
71
72# include <unistd.h>
73# include <fcntl.h>
74
75# define pipe_write(fd, buffer, size) write((fd), buffer, size)
76# define pipe_read(fd, buffer, size) read((fd), buffer, size)
77# define pipe_close(fd) close(fd)
78# define PIPE_FD_INVALID -1
79# define PIPE_FD_ERROR -1
80
81#endif /* ! _WIN32 */
82
83struct _Ecore_Pipe
84{
85 ECORE_MAGIC;
86 int fd_read;
87 int fd_write;
88 Ecore_Fd_Handler *fd_handler;
89 const void *data;
90 Ecore_Pipe_Cb handler;
91 unsigned int len;
92 int handling;
93 size_t already_read;
94 void *passed_data;
95 int message;
96 Eina_Bool delete_me : 1;
97};
98
99static Eina_Bool _ecore_pipe_read(void *data,
100 Ecore_Fd_Handler *fd_handler);
101
102/**
103 * @addtogroup Ecore_Pipe_Group
104 *
105 * @{
106 */
107
108/**
109 * Create two file descriptors (sockets on Windows). Add
110 * a callback that will be called when the file descriptor that
111 * is listened receives data. An event is also put in the event
112 * queue when data is received.
113 *
114 * @param handler The handler called when data is received.
115 * @param data Data to pass to @p handler when it is called.
116 * @return A newly created Ecore_Pipe object if successful.
117 * @c NULL otherwise.
118 */
119EAPI Ecore_Pipe *
120ecore_pipe_add(Ecore_Pipe_Cb handler,
121 const void *data)
122{
123 Ecore_Pipe *p;
124 int fds[2];
125
126 if (!handler) return NULL;
127
128 p = (Ecore_Pipe *)calloc(1, sizeof(Ecore_Pipe));
129 if (!p) return NULL;
130
131 if (pipe(fds))
132 {
133 free(p);
134 return NULL;
135 }
136
137 ECORE_MAGIC_SET(p, ECORE_MAGIC_PIPE);
138 p->fd_read = fds[0];
139 p->fd_write = fds[1];
140 p->handler = handler;
141 p->data = data;
142
143 fcntl(p->fd_read, F_SETFL, O_NONBLOCK);
144 p->fd_handler = ecore_main_fd_handler_add(p->fd_read,
145 ECORE_FD_READ,
146 _ecore_pipe_read,
147 p,
148 NULL, NULL);
149 return p;
150}
151
152/**
153 * Free an Ecore_Pipe object created with ecore_pipe_add().
154 *
155 * @param p The Ecore_Pipe object to be freed.
156 * @return The pointer to the private data
157 */
158EAPI void *
159ecore_pipe_del(Ecore_Pipe *p)
160{
161 void *data;
162
163 if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
164 {
165 ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_del");
166 return NULL;
167 }
168 p->delete_me = EINA_TRUE;
169 if (p->handling > 0) return (void *)p->data;
170 if (p->fd_handler) _ecore_main_fd_handler_del(p->fd_handler);
171 if (p->fd_read != PIPE_FD_INVALID) pipe_close(p->fd_read);
172 if (p->fd_write != PIPE_FD_INVALID) pipe_close(p->fd_write);
173 data = (void *)p->data;
174 free(p);
175 return data;
176}
177
178/**
179 * Close the read end of an Ecore_Pipe object created with ecore_pipe_add().
180 *
181 * @param p The Ecore_Pipe object.
182 */
183EAPI void
184ecore_pipe_read_close(Ecore_Pipe *p)
185{
186 if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
187 {
188 ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_close");
189 return;
190 }
191 if (p->fd_handler)
192 {
193 _ecore_main_fd_handler_del(p->fd_handler);
194 p->fd_handler = NULL;
195 }
196 if (p->fd_read != PIPE_FD_INVALID)
197 {
198 pipe_close(p->fd_read);
199 p->fd_read = PIPE_FD_INVALID;
200 }
201}
202
203/**
204 * Stop monitoring if necessary the pipe for reading. See ecore_pipe_thaw()
205 * for monitoring it again.
206 *
207 * @param p The Ecore_Pipe object.
208 * @since 1.1
209 */
210EAPI void
211ecore_pipe_freeze(Ecore_Pipe *p)
212{
213 if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
214 {
215 ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_freeze");
216 return;
217 }
218 if (p->fd_handler)
219 {
220 _ecore_main_fd_handler_del(p->fd_handler);
221 p->fd_handler = NULL;
222 }
223}
224
225/**
226 * Start monitoring again the pipe for reading. See ecore_pipe_freeze() for
227 * stopping the monitoring activity. This will not work if
228 * ecore_pipe_read_close() was previously called on the same pipe.
229 *
230 * @param p The Ecore_Pipe object.
231 * @since 1.1
232 */
233EAPI void
234ecore_pipe_thaw(Ecore_Pipe *p)
235{
236 if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
237 {
238 ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_thaw");
239 return;
240 }
241 if (!p->fd_handler && p->fd_read != PIPE_FD_INVALID)
242 {
243 p->fd_handler = ecore_main_fd_handler_add(p->fd_read,
244 ECORE_FD_READ,
245 _ecore_pipe_read,
246 p,
247 NULL, NULL);
248 }
249}
250
251/**
252 * @brief Wait from another thread on the read side of a pipe.
253 *
254 * @param p The pipe to watch on.
255 * @param message_count The minimal number of message to wait before exiting.
256 * @param wait The amount of time in second to wait before exiting.
257 * @return the number of message catched during that wait call.
258 * @since 1.1
259 *
260 * Negative value for @p wait means infite wait.
261 */
262EAPI int
263ecore_pipe_wait(Ecore_Pipe *p,
264 int message_count,
265 double wait)
266{
267 struct timeval tv, *t;
268 fd_set rset;
269 double end = 0.0;
270 double timeout;
271 int ret;
272 int total = 0;
273
274 if (p->fd_read == PIPE_FD_INVALID)
275 return -1;
276
277 FD_ZERO(&rset);
278 FD_SET(p->fd_read, &rset);
279
280 if (wait >= 0.0)
281 end = ecore_time_get() + wait;
282 timeout = wait;
283
284 while (message_count > 0 && (timeout > 0.0 || wait <= 0.0))
285 {
286 if (wait >= 0.0)
287 {
288 /* finite() tests for NaN, too big, too small, and infinity. */
289 if ((!ECORE_FINITE(timeout)) || (timeout == 0.0))
290 {
291 tv.tv_sec = 0;
292 tv.tv_usec = 0;
293 }
294 else if (timeout > 0.0)
295 {
296 int sec, usec;
297#ifdef FIX_HZ
298 timeout += (0.5 / HZ);
299 sec = (int)timeout;
300 usec = (int)((timeout - (double)sec) * 1000000);
301#else
302 sec = (int)timeout;
303 usec = (int)((timeout - (double)sec) * 1000000);
304#endif
305 tv.tv_sec = sec;
306 tv.tv_usec = usec;
307 }
308 t = &tv;
309 }
310 else
311 {
312 t = NULL;
313 }
314
315 ret = main_loop_select(p->fd_read + 1, &rset, NULL, NULL, t);
316
317 if (ret > 0)
318 {
319 _ecore_pipe_read(p, NULL);
320 message_count -= p->message;
321 total += p->message;
322 p->message = 0;
323 }
324 else if (ret == 0)
325 {
326 break;
327 }
328 else if (errno != EINTR)
329 {
330 close(p->fd_read);
331 p->fd_read = PIPE_FD_INVALID;
332 break;
333 }
334
335 if (wait >= 0.0)
336 timeout = end - ecore_time_get();
337 }
338
339 return total;
340}
341
342/**
343 * Close the write end of an Ecore_Pipe object created with ecore_pipe_add().
344 *
345 * @param p The Ecore_Pipe object.
346 */
347EAPI void
348ecore_pipe_write_close(Ecore_Pipe *p)
349{
350 if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
351 {
352 ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write_close");
353 return;
354 }
355 if (p->fd_write != PIPE_FD_INVALID)
356 {
357 pipe_close(p->fd_write);
358 p->fd_write = PIPE_FD_INVALID;
359 }
360}
361
362/**
363 * Write on the file descriptor the data passed as parameter.
364 *
365 * @param p The Ecore_Pipe object.
366 * @param buffer The data to write into the pipe.
367 * @param nbytes The size of the @p buffer in bytes
368 * @return Returns EINA_TRUE on a successful write, EINA_FALSE on an error
369 */
370EAPI Eina_Bool
371ecore_pipe_write(Ecore_Pipe *p,
372 const void *buffer,
373 unsigned int nbytes)
374{
375 ssize_t ret;
376 size_t already_written = 0;
377 int retry = ECORE_PIPE_WRITE_RETRY;
378
379 if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
380 {
381 ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write");
382 return EINA_FALSE;
383 }
384
385 if (p->delete_me) return EINA_FALSE;
386
387 if (p->fd_write == PIPE_FD_INVALID) return EINA_FALSE;
388
389 /* First write the len into the pipe */
390 do
391 {
392 ret = pipe_write(p->fd_write, &nbytes, sizeof(nbytes));
393 if (ret == sizeof(nbytes))
394 {
395 retry = ECORE_PIPE_WRITE_RETRY;
396 break;
397 }
398 else if (ret > 0)
399 {
400 /* XXX What should we do here? */
401 ERR("The length of the data was not written complete"
402 " to the pipe");
403 return EINA_FALSE;
404 }
405 else if (ret == PIPE_FD_ERROR && errno == EPIPE)
406 {
407 pipe_close(p->fd_write);
408 p->fd_write = PIPE_FD_INVALID;
409 return EINA_FALSE;
410 }
411 else if (ret == PIPE_FD_ERROR && errno == EINTR)
412 /* try it again */
413 ;
414 else
415 {
416 ERR("An unhandled error (ret: " FMT_SSIZE_T " errno: %d)"
417 "occurred while writing to the pipe the length",
418 ret, errno);
419 }
420 }
421 while (retry--);
422
423 if (retry != ECORE_PIPE_WRITE_RETRY) return EINA_FALSE;
424
425 /* and now pass the data to the pipe */
426 do
427 {
428 ret = pipe_write(p->fd_write,
429 ((unsigned char *)buffer) + already_written,
430 nbytes - already_written);
431
432 if (ret == (ssize_t)(nbytes - already_written))
433 return EINA_TRUE;
434 else if (ret >= 0)
435 {
436 already_written -= ret;
437 continue;
438 }
439 else if (ret == PIPE_FD_ERROR && errno == EPIPE)
440 {
441 pipe_close(p->fd_write);
442 p->fd_write = PIPE_FD_INVALID;
443 return EINA_FALSE;
444 }
445 else if (ret == PIPE_FD_ERROR && errno == EINTR)
446 /* try it again */
447 ;
448 else
449 {
450 ERR("An unhandled error (ret: " FMT_SSIZE_T " errno: %d)"
451 "occurred while writing to the pipe the length",
452 ret, errno);
453 }
454 }
455 while (retry--);
456
457 return EINA_FALSE;
458}
459
460/**
461 * @}
462 */
463
464/* Private function */
465static void
466_ecore_pipe_unhandle(Ecore_Pipe *p)
467{
468 p->handling--;
469 if (p->delete_me)
470 {
471 ecore_pipe_del(p);
472 }
473}
474
475static Eina_Bool
476_ecore_pipe_read(void *data,
477 Ecore_Fd_Handler *fd_handler __UNUSED__)
478{
479 Ecore_Pipe *p = (Ecore_Pipe *)data;
480 int i;
481
482 p->handling++;
483 for (i = 0; i < 16; i++)
484 {
485 ssize_t ret;
486
487 /* if we already have read some data we don't need to read the len
488 * but to finish the already started job
489 */
490 if (p->len == 0)
491 {
492 /* read the len of the passed data */
493 ret = pipe_read(p->fd_read, &p->len, sizeof(p->len));
494
495 /* catch the non error case first */
496 /* read amount ok - nothing more to do */
497 if (ret == sizeof(p->len))
498 ;
499 else if (ret > 0)
500 {
501 /* we got more data than we asked for - definite error */
502 ERR("Only read %i bytes from the pipe, although"
503 " we need to read %i bytes.",
504 (int)ret, (int)sizeof(p->len));
505 _ecore_pipe_unhandle(p);
506 return ECORE_CALLBACK_CANCEL;
507 }
508 else if (ret == 0)
509 {
510 /* we got no data */
511 if (i == 0)
512 {
513 /* no data on first try through means an error */
514 if (!p->delete_me)
515 p->handler((void *)p->data, NULL, 0);
516 if (p->passed_data) free(p->passed_data);
517 p->passed_data = NULL;
518 p->already_read = 0;
519 p->len = 0;
520 p->message++;
521 pipe_close(p->fd_read);
522 p->fd_read = PIPE_FD_INVALID;
523 p->fd_handler = NULL;
524 _ecore_pipe_unhandle(p);
525 return ECORE_CALLBACK_CANCEL;
526 }
527 else
528 {
529 /* no data after first loop try is ok */
530 _ecore_pipe_unhandle(p);
531 return ECORE_CALLBACK_RENEW;
532 }
533 }
534#ifndef _WIN32
535 else if ((ret == PIPE_FD_ERROR) &&
536 ((errno == EINTR) || (errno == EAGAIN)))
537 {
538 _ecore_pipe_unhandle(p);
539 return ECORE_CALLBACK_RENEW;
540 }
541 else
542 {
543 ERR("An unhandled error (ret: %i errno: %i [%s])"
544 "occurred while reading from the pipe the length",
545 (int)ret, errno, strerror(errno));
546 _ecore_pipe_unhandle(p);
547 return ECORE_CALLBACK_RENEW;
548 }
549#else
550 else /* ret == PIPE_FD_ERROR is the only other case on Windows */
551 {
552 if (WSAGetLastError() != WSAEWOULDBLOCK)
553 {
554 if (!p->delete_me)
555 p->handler((void *)p->data, NULL, 0);
556 if (p->passed_data) free(p->passed_data);
557 p->passed_data = NULL;
558 p->already_read = 0;
559 p->len = 0;
560 p->message++;
561 pipe_close(p->fd_read);
562 p->fd_read = PIPE_FD_INVALID;
563 p->fd_handler = NULL;
564 _ecore_pipe_unhandle(p);
565 return ECORE_CALLBACK_CANCEL;
566 }
567 }
568#endif
569 }
570
571 /* if somehow we got less than or equal to 0 we got an errnoneous
572 * messages so call callback with null and len we got. this case should
573 * never happen */
574 if (p->len == 0)
575 {
576 if (!p->delete_me)
577 p->handler((void *)p->data, NULL, 0);
578 /* reset all values to 0 */
579 if (p->passed_data) free(p->passed_data);
580 p->passed_data = NULL;
581 p->already_read = 0;
582 p->len = 0;
583 p->message++;
584 _ecore_pipe_unhandle(p);
585 return ECORE_CALLBACK_RENEW;
586 }
587
588 /* we dont have a buffer to hold the data, so alloc it */
589 if (!p->passed_data)
590 {
591 p->passed_data = malloc(p->len);
592 /* alloc failed - error case */
593 if (!p->passed_data)
594 {
595 if (!p->delete_me)
596 p->handler((void *)p->data, NULL, 0);
597 /* close the pipe */
598 p->already_read = 0;
599 p->len = 0;
600 p->message++;
601 pipe_close(p->fd_read);
602 p->fd_read = PIPE_FD_INVALID;
603 p->fd_handler = NULL;
604 _ecore_pipe_unhandle(p);
605 return ECORE_CALLBACK_CANCEL;
606 }
607 }
608
609 /* and read the passed data */
610 ret = pipe_read(p->fd_read,
611 ((unsigned char *)p->passed_data) + p->already_read,
612 p->len - p->already_read);
613
614 /* catch the non error case first */
615 /* if we read enough data to finish the message/buffer */
616 if (ret == (ssize_t)(p->len - p->already_read))
617 {
618 if (!p->delete_me)
619 p->handler((void *)p->data, p->passed_data, p->len);
620 free(p->passed_data);
621 /* reset all values to 0 */
622 p->passed_data = NULL;
623 p->already_read = 0;
624 p->len = 0;
625 p->message++;
626 }
627 else if (ret > 0)
628 {
629 /* more data left to read */
630 p->already_read += ret;
631 _ecore_pipe_unhandle(p);
632 return ECORE_CALLBACK_RENEW;
633 }
634 else if (ret == 0)
635 {
636 /* 0 bytes to read - could be more to read next select wake up */
637 _ecore_pipe_unhandle(p);
638 return ECORE_CALLBACK_RENEW;
639 }
640#ifndef _WIN32
641 else if ((ret == PIPE_FD_ERROR) &&
642 ((errno == EINTR) || (errno == EAGAIN)))
643 {
644 _ecore_pipe_unhandle(p);
645 return ECORE_CALLBACK_RENEW;
646 }
647 else
648 {
649 ERR("An unhandled error (ret: %zd errno: %d)"
650 "occurred while reading from the pipe the data",
651 ret, errno);
652 _ecore_pipe_unhandle(p);
653 return ECORE_CALLBACK_RENEW;
654 }
655#else
656 else /* ret == PIPE_FD_ERROR is the only other case on Windows */
657 {
658 if (WSAGetLastError() != WSAEWOULDBLOCK)
659 {
660 if (!p->delete_me)
661 p->handler((void *)p->data, NULL, 0);
662 if (p->passed_data) free(p->passed_data);
663 p->passed_data = NULL;
664 p->already_read = 0;
665 p->len = 0;
666 p->message++;
667 pipe_close(p->fd_read);
668 p->fd_read = PIPE_FD_INVALID;
669 p->fd_handler = NULL;
670 _ecore_pipe_unhandle(p);
671 return ECORE_CALLBACK_CANCEL;
672 }
673 else
674 break;
675 }
676#endif
677 }
678
679 _ecore_pipe_unhandle(p);
680 return ECORE_CALLBACK_RENEW;
681}
682