Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules / core / src / waitable_handle.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    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  * @file        waitable_handle.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of waitable handle
21  */
22 #include <stddef.h>
23 #include <dpl/waitable_event.h>
24 #include <dpl/workaround.h>
25 #include <sys/select.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <dpl/assert.h>
30
31 namespace DPL {
32 namespace // anonymous
33 {
34 void CheckWaitableHandle(WaitableHandle handle)
35 {
36 #ifdef DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK
37     // Try to get descriptor flags
38     int result = fcntl(handle, F_GETFL);
39
40     if (result == -1 && errno == EBADF) {
41         AssertMsg(0, "CheckWaitableHandle: Invalid WaitableHandle! (EBADF)");
42     }
43
44     AssertMsg(result != -1, "CheckWaitableHandle: Invalid WaitableHandle!");
45 #endif // DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK
46 }
47 } // namespace anonymous
48
49 WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle,
50                                             unsigned long miliseconds)
51 {
52     WaitableHandleList waitHandles;
53     waitHandles.push_back(handle);
54     return WaitForMultipleHandles(waitHandles, miliseconds);
55 }
56
57 WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle,
58                                             WaitMode::Type mode,
59                                             unsigned long miliseconds)
60 {
61     WaitableHandleListEx waitHandles;
62     waitHandles.push_back(std::make_pair(handle, mode));
63     return WaitForMultipleHandles(waitHandles, miliseconds);
64 }
65
66 WaitableHandleIndexList WaitForMultipleHandles(
67     const WaitableHandleList &waitableHandleList,
68     unsigned long miliseconds)
69 {
70     WaitableHandleListEx handleList;
71
72     for (WaitableHandleList::const_iterator iterator = waitableHandleList.begin();
73          iterator != waitableHandleList.end();
74          ++iterator)
75     {
76         // Wait for multiple objects
77         handleList.push_back(std::make_pair(*iterator, WaitMode::Read));
78     }
79
80     // Do waiting
81     return WaitForMultipleHandles(handleList, miliseconds);
82 }
83
84 WaitableHandleIndexList WaitForMultipleHandles(
85     const WaitableHandleListEx &waitableHandleListEx,
86     unsigned long miliseconds)
87 {
88     fd_set readFds, writeFds, errorFds;
89
90     // Fill sets
91     int maxFd = -1;
92
93     FD_ZERO(&readFds);
94     FD_ZERO(&writeFds);
95     FD_ZERO(&errorFds);
96
97     // Add read wait handles
98     for (WaitableHandleListEx::const_iterator iterator =
99              waitableHandleListEx.begin();
100          iterator != waitableHandleListEx.end();
101          ++iterator)
102     {
103         if (iterator->first > maxFd) {
104             maxFd = iterator->first;
105         }
106
107         CheckWaitableHandle(iterator->first);
108
109         // Handle errors along with read and write events
110         FD_SET(iterator->first, &errorFds);
111
112         if (iterator->second == WaitMode::Read) {
113             FD_SET(iterator->first, &readFds);
114         } else if (iterator->second == WaitMode::Write) {
115             FD_SET(iterator->first, &writeFds);
116         }
117     }
118
119     // Do select
120     timeval timeout;
121     timeval *effectiveTimeout = NULL;
122     if (miliseconds != 0xFFFFFFFF) {
123         timeout.tv_sec = miliseconds / 1000;
124         timeout.tv_usec = (miliseconds % 1000) * 1000;
125         effectiveTimeout = &timeout;
126     }
127
128     if (TEMP_FAILURE_RETRY(select(maxFd + 1, &readFds, &writeFds, &errorFds,
129                                   effectiveTimeout)) == -1)
130     {
131         Throw(WaitFailed);
132     }
133
134     // Check results
135     WaitableHandleIndexList indexes;
136     size_t index = 0;
137
138     for (WaitableHandleListEx::const_iterator iterator =
139              waitableHandleListEx.begin();
140          iterator != waitableHandleListEx.end();
141          ++iterator)
142     {
143         // Always return errors, no matter what type of listening is set
144         if (FD_ISSET(iterator->first, &errorFds)) {
145             indexes.push_back(index);
146         } else if (iterator->second == WaitMode::Read) {
147             if (FD_ISSET(iterator->first, &readFds)) {
148                 indexes.push_back(index);
149             }
150         } else if (iterator->second == WaitMode::Write) {
151             if (FD_ISSET(iterator->first, &writeFds)) {
152                 indexes.push_back(index);
153             }
154         }
155         ++index;
156     }
157
158     // Successfuly awaited some events or timeout occurred
159     return indexes;
160 }
161 } // namespace DPL