8e36bed2431619fcff5214145b5943e480f844c7
[platform/core/security/key-manager.git] / src / manager / common / 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 DescriptorSet::~DescriptorSet() {
34     purge();
35 }
36
37 void DescriptorSet::purge() {
38     for(auto it:m_descriptors)
39         close(it.first);
40     m_descriptors.clear();
41 }
42
43 void DescriptorSet::add(int fd, short events, Callback&& callback) {
44     // map operator[] requires empty DescriptorData constructor
45     auto it = m_descriptors.find(fd);
46     if (it == m_descriptors.end()) {
47         m_descriptors.insert(std::make_pair(fd,DescriptorData(events, std::move(callback))));
48     } else {
49         it->second.events = events;
50         it->second.callback = std::move(callback);
51     }
52     m_dirty = true;
53 }
54
55 void DescriptorSet::remove(int fd, bool close_fd) {
56     if (0 != m_descriptors.erase(fd)) {
57         if (close_fd)
58             close(fd);
59         m_dirty = true;
60     }
61 }
62
63 void DescriptorSet::wait(int timeout_ms) {
64     if(!rebuildPollfd())
65         return;
66
67     // wait
68     int ret = TEMP_FAILURE_RETRY(poll(m_fds, m_descriptors.size(), timeout_ms));
69     if (ret == 0) {
70         ThrowMsg(Timeout, "Poll timeout");
71     } else if (ret < 0) {
72         int err = errno;
73         ThrowMsg(InternalError, "Poll failed " << GetErrnoString(err));
74     }
75
76     notify(ret);
77 }
78
79 bool DescriptorSet::rebuildPollfd() {
80     if (m_dirty) {
81        delete[] m_fds;
82        m_fds = NULL;
83        if (m_descriptors.empty()) {
84            LogWarning("Nothing to wait for");
85            return false;
86        }
87
88        m_fds = new pollfd[m_descriptors.size()];
89        size_t idx = 0;
90        for(const auto& it : m_descriptors) {
91            m_fds[idx].fd = it.first;
92            m_fds[idx].events = it.second.events;
93            idx++;
94        }
95        m_dirty = false;
96     }
97     return true;
98 }
99
100 void DescriptorSet::notify(int descCount) {
101     size_t size = m_descriptors.size();
102     for(size_t idx = 0;idx < size;++idx) {
103         const pollfd& pfd = m_fds[idx];
104         if (pfd.revents == 0)
105             continue;
106
107         /*
108          * Descriptors can be added/removed inside observer callback but:
109          * 1. m_fds is not affected. It will be regenerated in next wait()
110          * 2. No m_descriptors iterator will be invalidated
111          * 3. m_descriptors size is stored in local variable
112          */
113         m_descriptors.at(pfd.fd).callback(pfd.fd, pfd.revents);
114         descCount--;
115
116         // no more descriptors to check
117         if (descCount == 0)
118             break;
119     }
120     if (descCount != 0)
121         ThrowMsg(InternalError, "Number of notified descriptors do not match");
122 }
123
124 } /* namespace CKM */