83442b2f116d1f2cd3a7683d1b9fa5859a014663
[platform/core/security/key-manager.git] / src / manager / client-async / descriptor-set.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 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       descriptor-set.cpp
18  * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
19  * @version    1.0
20  */
21
22 #include "descriptor-set.h"
23 #include <dpl/errno_string.h>
24 #include <dpl/log/log.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 namespace CKM {
29
30 DescriptorSet::DescriptorSet() : m_dirty(true), m_fds(NULL)
31 {
32 }
33
34 DescriptorSet::~DescriptorSet()
35 {
36         purge();
37 }
38
39 void DescriptorSet::purge()
40 {
41         for (auto it : m_descriptors)
42                 close(it.first);
43
44         m_descriptors.clear();
45 }
46
47 void DescriptorSet::add(int fd, short events, Callback &&callback)
48 {
49         // map operator[] requires empty DescriptorData constructor
50         auto it = m_descriptors.find(fd);
51
52         if (it == m_descriptors.end()) {
53                 m_descriptors.insert(std::make_pair(fd, DescriptorData(events,
54                                                                                         std::move(callback))));
55         } else {
56                 it->second.events = events;
57                 it->second.callback = std::move(callback);
58         }
59
60         m_dirty = true;
61 }
62
63 void DescriptorSet::remove(int fd, bool close_fd)
64 {
65         if (0 != m_descriptors.erase(fd)) {
66                 if (close_fd)
67                         close(fd);
68
69                 m_dirty = true;
70         }
71 }
72
73 void DescriptorSet::wait(int timeout_ms)
74 {
75         if (!rebuildPollfd())
76                 return;
77
78         // wait
79         int ret = TEMP_FAILURE_RETRY(poll(m_fds, m_descriptors.size(), timeout_ms));
80
81         if (ret == 0) {
82                 ThrowMsg(Timeout, "Poll timeout");
83         } else if (ret < 0) {
84                 int err = errno;
85                 ThrowMsg(InternalError, "Poll failed " << GetErrnoString(err));
86         }
87
88         notify(ret);
89 }
90
91 bool DescriptorSet::rebuildPollfd()
92 {
93         if (m_dirty) {
94                 delete[] m_fds;
95                 m_fds = NULL;
96
97                 if (m_descriptors.empty()) {
98                         LogWarning("Nothing to wait for");
99                         return false;
100                 }
101
102                 m_fds = new pollfd[m_descriptors.size()];
103                 size_t idx = 0;
104
105                 for (const auto &it : m_descriptors) {
106                         m_fds[idx].fd = it.first;
107                         m_fds[idx].events = it.second.events;
108                         idx++;
109                 }
110
111                 m_dirty = false;
112         }
113
114         return true;
115 }
116
117 void DescriptorSet::notify(int descCount)
118 {
119         size_t size = m_descriptors.size();
120
121         for (size_t idx = 0; idx < size; ++idx) {
122                 const pollfd &pfd = m_fds[idx];
123
124                 if (pfd.revents == 0)
125                         continue;
126
127                 /*
128                  * Descriptors can be added/removed inside observer callback but:
129                  * 1. m_fds is not affected. It will be regenerated in next wait()
130                  * 2. No m_descriptors iterator will be invalidated
131                  * 3. m_descriptors size is stored in local variable
132                  */
133                 m_descriptors.at(pfd.fd).callback(pfd.fd, pfd.revents);
134                 descCount--;
135
136                 // no more descriptors to check
137                 if (descCount == 0)
138                         break;
139         }
140
141         if (descCount != 0)
142                 ThrowMsg(InternalError, "Number of notified descriptors do not match");
143 }
144
145 } /* namespace CKM */