1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr.h"
18#include "apr_poll.h"
19#include "apr_time.h"
20#include "apr_portable.h"
21#include "apr_arch_file_io.h"
22#include "apr_arch_networkio.h"
23#include "apr_arch_poll_private.h"
24#include "apr_arch_inherit.h"
25
26#if !APR_FILES_AS_SOCKETS
27
28#ifdef WIN32
29
30apr_status_t apr_poll_create_wakeup_pipe(apr_pool_t *pool, apr_pollfd_t *pfd,
31                                         apr_file_t **wakeup_pipe)
32{
33    apr_status_t rv;
34
35    if ((rv = apr_file_socket_pipe_create(&wakeup_pipe[0], &wakeup_pipe[1],
36                                      pool)) != APR_SUCCESS)
37        return rv;
38
39    pfd->reqevents = APR_POLLIN;
40    pfd->desc_type = APR_POLL_FILE;
41    pfd->desc.f = wakeup_pipe[0];
42    return APR_SUCCESS;
43}
44
45apr_status_t apr_poll_close_wakeup_pipe(apr_file_t **wakeup_pipe)
46{
47    apr_status_t rv0 = APR_SUCCESS;
48    apr_status_t rv1 = APR_SUCCESS;
49
50    /* Close both sides of the wakeup pipe */
51    if (wakeup_pipe[0]) {
52        rv0 = apr_file_socket_pipe_close(wakeup_pipe[0]);
53        wakeup_pipe[0] = NULL;
54    }
55    if (wakeup_pipe[1]) {
56        rv1 = apr_file_socket_pipe_close(wakeup_pipe[1]);
57        wakeup_pipe[1] = NULL;
58    }
59    return rv0 ? rv0 : rv1;
60}
61
62#else /* !WIN32 */
63
64apr_status_t apr_poll_create_wakeup_pipe(apr_pollfd_t *pfd, apr_file_t **wakeup_pipe)
65{
66    return APR_ENOTIMPL;
67}
68
69apr_status_t apr_poll_close_wakeup_pipe(apr_file_t **wakeup_pipe)
70{
71    return APR_ENOTIMPL;
72}
73
74#endif /* !WIN32 */
75
76#else  /* APR_FILES_AS_SOCKETS */
77
78apr_status_t apr_poll_create_wakeup_pipe(apr_pool_t *pool, apr_pollfd_t *pfd,
79                                         apr_file_t **wakeup_pipe)
80{
81    apr_status_t rv;
82
83    if ((rv = apr_file_pipe_create(&wakeup_pipe[0], &wakeup_pipe[1],
84                                   pool)) != APR_SUCCESS)
85        return rv;
86
87    pfd->p = pool;
88    pfd->reqevents = APR_POLLIN;
89    pfd->desc_type = APR_POLL_FILE;
90    pfd->desc.f = wakeup_pipe[0];
91
92    {
93        int flags;
94
95        if ((flags = fcntl(wakeup_pipe[0]->filedes, F_GETFD)) == -1)
96            return errno;
97
98        flags |= FD_CLOEXEC;
99        if (fcntl(wakeup_pipe[0]->filedes, F_SETFD, flags) == -1)
100            return errno;
101    }
102    {
103        int flags;
104
105        if ((flags = fcntl(wakeup_pipe[1]->filedes, F_GETFD)) == -1)
106            return errno;
107
108        flags |= FD_CLOEXEC;
109        if (fcntl(wakeup_pipe[1]->filedes, F_SETFD, flags) == -1)
110            return errno;
111    }
112
113    return APR_SUCCESS;
114}
115
116apr_status_t apr_poll_close_wakeup_pipe(apr_file_t **wakeup_pipe)
117{
118    apr_status_t rv0 = APR_SUCCESS;
119    apr_status_t rv1 = APR_SUCCESS;
120
121    /* Close both sides of the wakeup pipe */
122    if (wakeup_pipe[0]) {
123        rv0 = apr_file_close(wakeup_pipe[0]);
124        wakeup_pipe[0] = NULL;
125    }
126    if (wakeup_pipe[1]) {
127        rv1 = apr_file_close(wakeup_pipe[1]);
128        wakeup_pipe[1] = NULL;
129    }
130    return rv0 ? rv0 : rv1;
131}
132
133#endif /* APR_FILES_AS_SOCKETS */
134
135/* Read and discard whatever is in the wakeup pipe.
136 */
137void apr_poll_drain_wakeup_pipe(apr_file_t **wakeup_pipe)
138{
139    char rb[512];
140    apr_size_t nr = sizeof(rb);
141
142    while (apr_file_read(wakeup_pipe[0], rb, &nr) == APR_SUCCESS) {
143        /* Although we write just one byte to the other end of the pipe
144         * during wakeup, multiple threads could call the wakeup.
145         * So simply drain out from the input side of the pipe all
146         * the data.
147         */
148        if (nr != sizeof(rb))
149            break;
150    }
151}
152