Mir

Merge lp:~kdub/mir/fd-refcount into lp:mir

Proposed by Kevin DuBois
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 1807
Proposed branch: lp:~kdub/mir/fd-refcount
Merge into: lp:mir
Diff against target: 170 lines (+98/-13)
4 files modified
include/shared/mir/fd.h (+4/-2)
src/shared/fd/fd.cpp (+12/-11)
tests/unit-tests/CMakeLists.txt (+1/-0)
tests/unit-tests/test_fd.cpp (+81/-0)
To merge this branch: bzr merge lp:~kdub/mir/fd-refcount
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Chris Halse Rogers Abstain
PS Jenkins bot (community) continuous-integration Approve
Alexandros Frantzis (community) Approve
Review via email: mp+228306@code.launchpad.net

Commit message

make the mir::Fd type CopyConstructible (and also CopyAssignable)

Description of the change

make the mir::Fd type CopyConstructible (and also CopyAssignable)

the Fd type that landed a bit earlier this week was MoveConstructible/MoveAssignable, but there's no reason it can't be CopyConstructible/Assignable. This could be done via dup(), but that entails an extra hop to the kernel, so I implemented refcounting for the raw fd instead of using dup.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

26 + struct CountedFd
27 + {
28 + CountedFd(int fd);
29 + int const raw_fd;
30 + std::atomic<unsigned int> refcount;
31 + };
32 + CountedFd *fd;

Use a std::shared_ptr<int> (with a custom deleter)?

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

@"This could be done via dup()"

Can it? doesn't that, for example, lose FD_CLOEXEC.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> 26 + struct CountedFd
> 27 + {
> 28 + CountedFd(int fd);
> 29 + int const raw_fd;
> 30 + std::atomic<unsigned int> refcount;
> 31 + };
> 32 + CountedFd *fd;
>
> Use a std::shared_ptr<int> (with a custom deleter)?

Yes. That's simpler.

review: Needs Fixing
Revision history for this message
Kevin DuBois (kdub) wrote :

But isn't it more fun to read new hand-crafted, artisan code instead of mass produced code? (kidding)
Updated to use shared_ptr<>, it is a bit cleaner.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

17 + Fd(Fd const&);
...
51 +mir::Fd::Fd(Fd const& other) :
52 + fd{other.fd}
53 {
54 }

Can be even simpler:

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

> @"This could be done via dup()"
>
> Can it? doesn't that, for example, lose FD_CLOEXEC.

Not if you use dup2().

That said, std::shared_ptr does the job admirably.

Not blocking, but I *think* you could use std::shared_ptr<int const> now, throw when constructing from an invalid fd, and drop the conditional in the shared_ptr's deleter?

While we're at it, is there any reason not to make operator int() throw when called on an invalid fd?

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

OK.

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

@Chris, I'm shying away from throwing on invalid fds because some code has the concept of an invalid fd, and it sometimes needs to access the invalid fd without throwing. (thinking mostly of some of the hwc classes)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

Looking through MPs to see how other peopel are dealing with this sha1sums file...shouldn't include/shared/mir/fd.h be in server sha1sums?

Revision history for this message
Chris Halse Rogers (raof) wrote :

> @Chris, I'm shying away from throwing on invalid fds because some code has the
> concept of an invalid fd, and it sometimes needs to access the invalid fd
> without throwing. (thinking mostly of some of the hwc classes)

Urgh, ok :(

review: Abstain
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

> Looking through MPs to see how other peopel are dealing with this sha1sums
> file...shouldn't include/shared/mir/fd.h be in server sha1sums?

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

> > Looking through MPs to see how other peopel are dealing with this sha1sums
> > file...shouldn't include/shared/mir/fd.h be in server sha1sums?

+1

(Misclicked earlier)

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> Looking through MPs to see how other peopel are dealing with this sha1sums
> file...shouldn't include/shared/mir/fd.h be in server sha1sums?

It should once it is pushed to distro. (ABI versioning doesn't apply until then.)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/shared/mir/fd.h'
2--- include/shared/mir/fd.h 2014-07-14 14:52:08 +0000
3+++ include/shared/mir/fd.h 2014-07-29 16:48:39 +0000
4@@ -18,6 +18,8 @@
5 #ifndef MIR_FD_H_
6 #define MIR_FD_H_
7
8+#include <memory>
9+
10 namespace mir
11 {
12 class Fd
13@@ -29,14 +31,14 @@
14 static int const invalid{-1};
15 Fd(); //Initializes fd to the mir::Fd::invalid;
16 Fd(Fd&&);
17+ Fd(Fd const&) = default;
18 Fd& operator=(Fd);
19- ~Fd() noexcept;
20
21 //bit of a convenient kludge. take care not to close or otherwise destroy the FD.
22 operator int() const;
23
24 private:
25- int fd;
26+ std::shared_ptr<int> fd;
27 };
28 } // namespace mir
29
30
31=== modified file 'src/shared/fd/fd.cpp'
32--- src/shared/fd/fd.cpp 2014-07-14 14:52:08 +0000
33+++ src/shared/fd/fd.cpp 2014-07-29 16:48:39 +0000
34@@ -24,20 +24,20 @@
35 {
36 }
37
38-mir::Fd::Fd(int other_fd) :
39- fd{other_fd}
40+mir::Fd::Fd(int raw_fd) :
41+ fd{new int{raw_fd},
42+ [](int* fd)
43+ {
44+ if (!fd) return;
45+ if (*fd > mir::Fd::invalid) ::close(*fd);
46+ delete fd;
47+ }}
48 {
49 }
50
51 mir::Fd::Fd(Fd&& other) :
52- fd{other.fd}
53-{
54- other.fd = invalid;
55-}
56-
57-mir::Fd::~Fd() noexcept
58-{
59- if (fd > invalid) ::close(fd);
60+ fd{std::move(other.fd)}
61+{
62 }
63
64 mir::Fd& mir::Fd::operator=(Fd other)
65@@ -48,5 +48,6 @@
66
67 mir::Fd::operator int() const
68 {
69- return fd;
70+ if (fd) return *fd;
71+ return invalid;
72 }
73
74=== modified file 'tests/unit-tests/CMakeLists.txt'
75--- tests/unit-tests/CMakeLists.txt 2014-07-28 16:26:39 +0000
76+++ tests/unit-tests/CMakeLists.txt 2014-07-29 16:48:39 +0000
77@@ -20,6 +20,7 @@
78 test_thread_name.cpp
79 test_default_emergency_cleanup.cpp
80 test_basic_observers.cpp
81+ test_fd.cpp
82 )
83
84 add_subdirectory(options/)
85
86=== added file 'tests/unit-tests/test_fd.cpp'
87--- tests/unit-tests/test_fd.cpp 1970-01-01 00:00:00 +0000
88+++ tests/unit-tests/test_fd.cpp 2014-07-29 16:48:39 +0000
89@@ -0,0 +1,81 @@
90+/*
91+ * Copyright © 2014 Canonical Ltd.
92+ *
93+ * This program is free software: you can redistribute it and/or modify
94+ * it under the terms of the GNU General Public License version 3 as
95+ * published by the Free Software Foundation.
96+ *
97+ * This program is distributed in the hope that it will be useful,
98+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
99+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
100+ * GNU General Public License for more details.
101+ *
102+ * You should have received a copy of the GNU General Public License
103+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
104+ *
105+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
106+ */
107+
108+#include "mir/fd.h"
109+#include <gtest/gtest.h>
110+#include <gmock/gmock.h>
111+#include <unistd.h>
112+#include <fcntl.h>
113+#include <stdio.h>
114+
115+namespace
116+{
117+
118+bool fd_is_open(int fd)
119+{
120+ return fcntl(fd, F_GETFD) != -1;
121+}
122+
123+struct Fd : public testing::Test
124+{
125+ Fd() :
126+ raw_fd(::open("/dev/null", 0))
127+ {
128+ }
129+
130+ ~Fd()
131+ {
132+ if (fd_is_open(raw_fd))
133+ ::close(raw_fd);
134+ }
135+
136+ int const raw_fd;
137+};
138+}
139+
140+TEST_F(Fd, closes_when_refcount_is_zero)
141+{
142+ EXPECT_TRUE(fd_is_open(raw_fd));
143+ mir::Fd fd2(-1);
144+ {
145+ mir::Fd fd(raw_fd);
146+ {
147+ mir::Fd fd1(fd);
148+ fd2 = fd1;
149+ }
150+ }
151+
152+ EXPECT_TRUE(fd_is_open(raw_fd));
153+ fd2 = mir::Fd(-1);
154+ EXPECT_FALSE(fd_is_open(raw_fd));
155+}
156+
157+TEST_F(Fd, moves_around)
158+{
159+ EXPECT_TRUE(fd_is_open(raw_fd));
160+ mir::Fd fd0(-1);
161+ fd0 = mir::Fd(raw_fd);
162+ mir::Fd fd1(std::move(fd0));
163+ mir::Fd fd2(fd1);
164+
165+ EXPECT_TRUE(fd_is_open(raw_fd));
166+ fd1 = mir::Fd(-1);
167+ EXPECT_TRUE(fd_is_open(raw_fd));
168+ fd2 = mir::Fd(-1);
169+ EXPECT_FALSE(fd_is_open(raw_fd));
170+}

Subscribers

People subscribed via source and target branches