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