tizen beta release
[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 <dpl/waitable_event.h>
23 #include <dpl/workaround.h>
24 #include <dpl/log/log.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 {
33 namespace // anonymous
34 {
35 void CheckWaitableHandle(WaitableHandle handle)
36 {
37 #ifdef DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK
38     // Try to get descriptor flags
39     int result = fcntl(handle, F_GETFL);
40
41     if (result == -1 && errno == EBADF)
42         Assert(0 && "CheckWaitableHandle: Invalid WaitableHandle! (EBADF)");
43
44     Assert(result != -1 && "CheckWaitableHandle: Invalid WaitableHandle!");
45 #endif // DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK
46 }
47 } // namespace anonymous
48
49 WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle, unsigned long miliseconds)
50 {
51     WaitableHandleList waitHandles;
52     waitHandles.push_back(handle);
53     return WaitForMultipleHandles(waitHandles, miliseconds);
54 }
55
56 WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle, WaitMode::Type mode, unsigned long miliseconds)
57 {
58     WaitableHandleListEx waitHandles;
59     waitHandles.push_back(std::make_pair(handle, mode));
60     return WaitForMultipleHandles(waitHandles, miliseconds);
61 }
62
63 WaitableHandleIndexList WaitForMultipleHandles(const WaitableHandleList &waitableHandleList, unsigned long miliseconds)
64 {
65     WaitableHandleListEx handleList;
66
67     for (WaitableHandleList::const_iterator iterator = waitableHandleList.begin();
68          iterator != waitableHandleList.end();
69          ++iterator)
70     {
71         // Wait for multiple objects
72         handleList.push_back(std::make_pair(*iterator, WaitMode::Read));
73     }
74
75     // Do waiting
76     return WaitForMultipleHandles(handleList, miliseconds);
77 }
78
79 WaitableHandleIndexList WaitForMultipleHandles(const WaitableHandleListEx &waitableHandleListEx, unsigned long miliseconds)
80 {
81     fd_set readFds, writeFds, errorFds;
82
83     // Fill sets
84     int maxFd = -1;
85
86     FD_ZERO(&readFds);
87     FD_ZERO(&writeFds);
88     FD_ZERO(&errorFds);
89
90     // Add read wait handles
91     for (WaitableHandleListEx::const_iterator iterator = waitableHandleListEx.begin();
92          iterator != waitableHandleListEx.end();
93          ++iterator)
94     {
95         if (iterator->first > maxFd)
96             maxFd = iterator->first;
97
98         CheckWaitableHandle(iterator->first);
99
100         // Handle errors along with read and write events
101         FD_SET(iterator->first, &errorFds);
102
103         if (iterator->second == WaitMode::Read)
104         {
105             FD_SET(iterator->first, &readFds);
106         }
107         else if (iterator->second == WaitMode::Write)
108         {
109             FD_SET(iterator->first, &writeFds);
110         }
111     }
112
113     // Do select
114     timeval timeout;
115     timeval *effectiveTimeout = NULL;
116     if (miliseconds != 0xFFFFFFFF) {
117         timeout.tv_sec = miliseconds / 1000;
118         timeout.tv_usec = (miliseconds % 1000) * 1000;
119         effectiveTimeout = &timeout;
120     }
121
122     if (TEMP_FAILURE_RETRY(select(maxFd + 1, &readFds, &writeFds, &errorFds, effectiveTimeout)) == -1)
123         Throw(WaitFailed);
124
125     // Check results
126     WaitableHandleIndexList indexes;
127     size_t index = 0;
128
129     for (WaitableHandleListEx::const_iterator iterator = waitableHandleListEx.begin();
130          iterator != waitableHandleListEx.end();
131          ++iterator)
132     {
133         // Always return errors, no matter what type of listening is set
134         if (FD_ISSET(iterator->first, &errorFds)) {
135             indexes.push_back(index);
136         }
137         else if (iterator->second == WaitMode::Read)
138         {
139             if (FD_ISSET(iterator->first, &readFds))
140                 indexes.push_back(index);
141         }
142         else if (iterator->second == WaitMode::Write)
143         {
144             if (FD_ISSET(iterator->first, &writeFds))
145                 indexes.push_back(index);
146         }
147         ++index;
148     }
149
150     // Successfuly awaited some events or timeout occurred
151     return indexes;
152 }
153 } // namespace DPL