Tamer
C++ language extensions for event-driven programming
Loading...
Searching...
No Matches
fd.hh
Go to the documentation of this file.
1#ifndef TAMER_FD_HH
2#define TAMER_FD_HH 1
3/* Copyright (c) 2007-2015, Eddie Kohler
4 * Copyright (c) 2007, Regents of the University of California
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, subject to the conditions
9 * listed in the Tamer LICENSE file. These conditions include: you must
10 * preserve this copyright notice, and you cannot mention the copyright
11 * holders in advertising related to the Software without their permission.
12 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
13 * notice is a summary of the Tamer LICENSE file; the license in that file is
14 * legally binding.
15 */
16#include <tamer/tamer.hh>
17#include <tamer/lock.hh>
18#include <unistd.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <sys/socket.h>
22#include <sys/uio.h>
23#include <netinet/in.h>
24#include <vector>
25#include <string>
26namespace tamer {
27
31
32class fd {
33 struct fdimp;
34
35 public:
36 enum { default_backlog = 128 };
37
38 inline fd();
39 explicit inline fd(int f);
40 inline fd(const fd& f);
41 inline fd(fd&& f);
42 inline ~fd();
43
44 inline fd& operator=(const fd& f);
45 inline fd& operator=(fd&& f);
46
47 static void open(const char* filename, int flags, mode_t mode,
48 event<fd> result);
49 static inline void open(const char* filename, int flags, event<fd> result);
50 static fd open(const char* filename, int flags, mode_t mode = 0777);
51
52 static fd socket(int domain, int type, int protocol);
53 static int pipe(fd& rfd, fd& wfd);
54 static inline int pipe(fd pfd[2]);
55
56 inline bool valid() const;
57 inline explicit operator bool() const;
58 inline int error() const;
59 inline int fdnum() const;
60 inline int recent_fdnum() const;
61
62 inline void at_close(event<> e);
63 event<> closer();
64 inline void close(event<int> done);
65 inline void close();
66 inline void close(int errcode);
67 inline void error_close(int errcode);
68
69 void read(void* buf, size_t size, size_t* nread_ptr, event<int> done);
70 inline void read(void* buf, size_t size, size_t& nread, event<int> done);
71 inline void read(void* buf, size_t size, size_t& nread, event<> done);
72 inline void read(void* buf, size_t size, event<int> done);
73 inline void read(void* buf, size_t size, event<> done);
74 void read(struct iovec* iov, int iov_count, size_t* nread_ptr, event<int> done);
75 inline void read(struct iovec* iov, int iov_count, size_t& nread, event<int> done);
76 inline void read(struct iovec* iov, int iov_count, size_t& nread, event<> done);
77 void read_once(void* buf, size_t size, size_t& nread, event<int> done);
78 inline void read_once(void* buf, size_t size, size_t& nread, event<> done);
79 void read_once(const struct iovec* iov, int iov_count, size_t& nread, event<int> done);
80 inline void read_once(const struct iovec* iov, int iov_count, size_t& nread, event<> done);
81
82 void write(const void* buf, size_t size, size_t* nwritten_ptr, event<int> done);
83 inline void write(const void* buf, size_t size, size_t& nwritten, event<int> done);
84 inline void write(const void* buf, size_t size, size_t& nwritten, event<> done);
85 inline void write(const void* buf, size_t size, event<int> done);
86 inline void write(const void* buf, size_t size, event<> done);
87 void write(std::string buf, size_t* nwritten_ptr, event<int> done);
88 inline void write(const std::string& buf, size_t& nwritten, event<int> done);
89 inline void write(const std::string& buf, size_t& nwritten, event<> done);
90 inline void write(const std::string& buf, event<int> done);
91 inline void write(const std::string& buf, event<> done);
92 void write(struct iovec* iov, int iov_count, size_t* nwritten_ptr, event<int> done);
93 inline void write(struct iovec* iov, int iov_count, size_t& nwritten, event<int> done);
94 inline void write(struct iovec* iov, int iov_count, size_t& nwritten, event<> done);
95 void write_once(const void* buf, size_t size, size_t& nwritten, event<int> done);
96 inline void write_once(const void* buf, size_t size, size_t& nwritten, event<> done);
97 void write_once(const struct iovec* iov, int iov_count, size_t& nwritten, event<int> done);
98 inline void write_once(const struct iovec* iov, int iov_count, size_t& nwritten, event<> done);
99 bool write_closed() const;
100
101 void sendmsg(const void* buf, size_t size, int transfer_fd, event<int> done);
102 inline void sendmsg(const void* buf, size_t size, event<int> done);
103
104 void fstat(struct stat& stat, event<int> done);
105
106 int listen(int backlog = default_backlog);
107 int bind(const struct sockaddr* addr, socklen_t addrlen);
108 void accept(struct sockaddr* addr, socklen_t* addrlen, event<fd> result);
109 inline void accept(event<fd> result);
110 void connect(const struct sockaddr* addr, socklen_t addrlen,
111 event<int> done);
112 inline int shutdown(int how);
113 inline int socket_error() const;
114
115 ssize_t direct_read(void* buf, size_t size);
116 ssize_t direct_write(const void* buf, size_t size);
117
118 static int open_limit();
119 static int open_limit(int n);
120
121 static int make_nonblocking(int f);
122 static int make_blocking(int f);
123 inline int make_nonblocking();
124
125 private:
126 struct fdimp {
127 int fde_;
128 int fdv_;
129 mutex rlock_;
130 mutex wlock_;
131 event<> _at_close;
132#if HAVE_TAMER_FDHELPER
133 bool _is_file;
134#endif
135 unsigned ref_count_;
136 unsigned weak_count_;
137
138 fdimp(int fd)
139 : fde_(fd < 0 ? fd : 0), fdv_(fd)
140#if HAVE_TAMER_FDHELPER
141 , _is_file(false)
142#endif
143 , ref_count_(1), weak_count_(0) {
144 }
145 void deref() {
146 if (!--ref_count_)
147 close();
148 if (!ref_count_ && !weak_count_)
149 delete this;
150 }
151 void weak_deref() {
152 if (!--weak_count_ && !ref_count_)
153 delete this;
154 }
155 int close(int leave_error = -EBADF);
156 };
157
158 struct fdcloser {
159 fdcloser(fd::fdimp* imp)
160 : imp_(imp) {
161 ++imp_->weak_count_;
162 }
163 ~fdcloser() {
164 imp_->weak_deref();
165 }
166 void operator()() {
167 imp_->close();
168 }
169 fd::fdimp* imp_;
170 };
171
172 class closure__accept__P8sockaddrP9socklen_tQ2fd_; void accept(closure__accept__P8sockaddrP9socklen_tQ2fd_&);
173 class closure__connect__PK8sockaddr9socklen_tQi_; void connect(closure__connect__PK8sockaddr9socklen_tQi_&);
174 class closure__read__PvkPkQi_; void read(closure__read__PvkPkQi_&);
175 class closure__read__P5ioveciPkQi_; void read(closure__read__P5ioveciPkQi_&);
176 class closure__read_once__PvkRkQi_; void read_once(closure__read_once__PvkRkQi_ &);
177 class closure__read_once__PK5ioveciRkQi_; void read_once(closure__read_once__PK5ioveciRkQi_&);
178 class closure__write__PKvkPkQi_; void write(closure__write__PKvkPkQi_ &);
179 class closure__write__SsPkQi_; void write(closure__write__SsPkQi_ &);
180 class closure__write__P5ioveciPkQi_; void write(closure__write__P5ioveciPkQi_&);
181 class closure__write_once__PKvkRkQi_; void write_once(closure__write_once__PKvkRkQi_ &);
182 class closure__write_once__PK5ioveciRkQi_; void write_once(closure__write_once__PK5ioveciRkQi_&);
183 class closure__sendmsg__PKvkiQi_; void sendmsg(closure__sendmsg__PKvkiQi_ &);
184 class closure__open__PKci6mode_tQ2fd_; static void open(closure__open__PKci6mode_tQ2fd_ &);
185
186 fdimp* _p;
187
188 friend bool operator==(const fd &a, const fd &b);
189 friend bool operator!=(const fd &a, const fd &b);
190 friend class fdref;
191};
192
193class fdref {
194 public:
195 enum ref_type { strong = 0, weak = 1 };
196 inline fdref();
197 explicit inline fdref(const fd& f);
198 explicit inline fdref(fd&& f);
199 inline fdref(const fd& f, ref_type ref);
200 inline fdref(fd&& f, ref_type ref);
201 inline ~fdref();
202
203 inline explicit operator bool() const;
204 inline int fdnum() const;
205
206 inline void acquire_read(event<> done);
207 inline void release_read();
208 inline ssize_t read(void* buf, size_t size);
209
210 inline void acquire_write(event<> done);
211 inline void release_write();
212 inline ssize_t write(const void* buf, size_t size);
213
214 inline void close();
215 inline void close(int errcode);
216
217 private:
218 enum { read_locked = 2, write_locked = 4 };
219 fd::fdimp* imp_;
220 int flags_;
221
222 fdref(const fdref&) = delete;
223 fdref& operator=(const fdref&) = delete;
224
225 friend class fd;
226};
227
228inline fd tcp_listen(int port);
229fd tcp_listen(int port, int backlog);
230inline void tcp_listen(int port, event<fd> result);
231void tcp_listen(int port, int backlog, event<fd> result);
232void tcp_connect(struct in_addr addr, int port, event<fd> result);
233inline void tcp_connect(int port, event<fd> result);
234
235void udp_connect(struct in_addr addr, int port, event<fd> result);
236
237fd unix_stream_listen(std::string path, int backlog);
238inline fd unix_stream_listen(std::string path);
239void unix_stream_connect(std::string path, event<fd> result);
240
241
242struct exec_fd {
243 enum fdtype {
244 fdtype_newin, fdtype_newout, fdtype_share, fdtype_transfer
245 };
246 int child_fd;
247 fdtype type;
248 fd f;
249 inline exec_fd(int child_fd, fdtype type, fd f = fd());
250};
251
252pid_t exec(std::vector<exec_fd>& exec_fds, const char* program, bool path,
253 const std::vector<const char*> &argv, char* const envp[]);
254inline pid_t execv(fd& in, fd& out, const char* program,
255 const std::vector<const char*>& argv);
256inline pid_t execv(fd& in, fd& out, fd& err, const char* program,
257 const std::vector<const char*>& argv);
258inline pid_t execvp(fd& in, fd& out, const char* program,
259 const std::vector<const char*>& argv);
260inline pid_t execvp(fd& in, fd& out, fd& err, const char* program,
261 const std::vector<const char*>& argv);
262
263
269inline fd::fd()
270 : _p() {
271}
272
283inline fd::fd(int value)
284 : _p(value == -EBADF ? 0 : new fdimp(value)) {
285}
286
295inline fd::fd(const fd &f)
296 : _p(f._p) {
297 if (_p)
298 ++_p->ref_count_;
299}
300
301inline fd::fd(fd&& f)
302 : _p(f._p) {
303 f._p = 0;
304}
305
310inline fd::~fd() {
311 if (_p)
312 _p->deref();
313}
314
318inline fd& fd::operator=(const fd& f) {
319 if (f._p)
320 ++f._p->ref_count_;
321 if (_p)
322 _p->deref();
323 _p = f._p;
324 return *this;
325}
326
327inline fd& fd::operator=(fd&& f) {
328 if (_p)
329 _p->deref();
330 _p = f._p;
331 f._p = 0;
332 return *this;
333}
334
345inline void fd::open(const char* filename, int flags, event<fd> f) {
346 open(filename, flags, 0777, f);
347}
348
355inline int fd::pipe(fd pfd[2]) {
356 return pipe(pfd[0], pfd[1]);
357}
358
362inline bool fd::valid() const {
363 return _p && _p->fde_ >= 0;
364}
365
369inline fd::operator bool() const {
370 return _p && _p->fde_ >= 0;
371}
372
377inline int fd::error() const {
378 return _p ? _p->fde_ : -EBADF;
379}
380
385inline int fd::fdnum() const {
386 assert(_p && _p->fde_ >= 0);
387 return _p->fdv_;
388}
389
393inline int fd::recent_fdnum() const {
394 return _p ? _p->fdv_ : -EBADF;
395}
396
404inline void fd::at_close(event<> e) {
405 if (*this) {
406 _p->_at_close += std::move(e);
407 } else {
408 e();
409 }
410}
411
417inline void fd::close(event<int> done)
418{
419 done.trigger(*this ? _p->close() : -EBADF);
420}
421
424inline void fd::close()
425{
426 if (_p) {
427 _p->close();
428 }
429}
430
436inline void fd::accept(event<fd> result) {
437 accept(0, 0, result);
438}
439
442inline int fd::shutdown(int how) {
443 if (_p && _p->fde_ >= 0)
444 return ::shutdown(_p->fdv_, how);
445 else
446 return -EBADF;
447}
448
450inline int fd::socket_error() const {
451 if (_p && _p->fde_ >= 0) {
452 int error = 0;
453 socklen_t len = sizeof(error);
454 int r = getsockopt(_p->fdv_, SOL_SOCKET, SO_ERROR, &error, &len);
455 return r ? -error : 0;
456 } else {
457 return -EBADF;
458 }
459}
460
474inline void fd::read(void* buf, size_t size, size_t& nread, event<int> done) {
475 read(buf, size, &nread, done);
476}
477
478inline void fd::read(void* buf, size_t size, size_t& nread, event<> done) {
479 read(buf, size, &nread, rebind<int>(done));
480}
481
492inline void fd::read(void* buf, size_t size, event<int> done) {
493 read(buf, size, (size_t*) 0, done);
494}
495
496inline void fd::read(void* buf, size_t size, event<> done) {
497 read(buf, size, (size_t*) 0, rebind<int>(done));
498}
499
514inline void fd::read(struct iovec* iov, int iov_count, size_t& nread, event<int> done) {
515 read(iov, iov_count, &nread, done);
516}
517
518inline void fd::read(struct iovec* iov, int iov_count, size_t& nread, event<> done) {
519 read(iov, iov_count, &nread, rebind<int>(done));
520}
521
537inline void fd::read_once(void *buf, size_t size, size_t& nread, event<> done) {
538 read_once(buf, size, nread, rebind<int>(done));
539}
540
556inline void fd::read_once(const struct iovec* iov, int iov_count, size_t& nread, event<> done) {
557 read_once(iov, iov_count, nread, rebind<int>(done));
558}
559
560
572inline void fd::write(const void *buf, size_t size, size_t& nwritten, event<int> done) {
573 write(buf, size, &nwritten, done);
574}
575
576inline void fd::write(const void *buf, size_t size, size_t& nwritten, event<> done) {
577 write(buf, size, &nwritten, rebind<int>(done));
578}
579
592inline void fd::write(struct iovec* iov, int iov_count, size_t& nwritten, event<int> done) {
593 write(iov, iov_count, &nwritten, done);
594}
595
596inline void fd::write(struct iovec* iov, int iov_count, size_t& nwritten, event<> done) {
597 write(iov, iov_count, &nwritten, rebind<int>(done));
598}
599
608inline void fd::write(const void *buf, size_t size, event<int> done) {
609 write(buf, size, 0, done);
610}
611
612inline void fd::write(const void *buf, size_t size, event<> done) {
613 write(buf, size, 0, rebind<int>(done));
614}
615
623inline void fd::write(const std::string& buf, size_t& nwritten, event<int> done) {
624 write(buf, &nwritten, done);
625}
626
627inline void fd::write(const std::string& buf, size_t& nwritten, event<> done) {
628 write(buf, &nwritten, rebind<int>(done));
629}
630
637inline void fd::write(const std::string& buf, event<int> done) {
638 write(buf, (size_t*) 0, done);
639}
640
641inline void fd::write(const std::string &buf, event<> done) {
642 write(buf, (size_t*) 0, rebind<int>(done));
643}
644
645inline void fd::write_once(const void *buf, size_t size, size_t& nwritten, event<> done) {
646 write_once(buf, size, nwritten, rebind<int>(done));
647}
648
649inline void fd::write_once(const struct iovec* iov, int iov_count, size_t& nwritten, event<> done) {
650 write_once(iov, iov_count, nwritten, rebind<int>(done));
651}
652
653
655inline void fd::sendmsg(const void *buf, size_t size, event<int> done) {
656 sendmsg(buf, size, -1, done);
657}
658
665inline void fd::close(int errcode) {
666 if (_p)
667 _p->close(errcode);
668 else if (errcode < 0 && errcode != -EBADF)
669 _p = new fdimp(errcode);
670}
671
673inline void fd::error_close(int errcode) {
674 close(errcode);
675}
677
680inline int fd::make_nonblocking() {
681 return make_nonblocking(_p ? _p->fde_ : -EBADF);
682}
683
689inline bool operator==(const fd &a, const fd &b) {
690 return a._p == b._p;
691}
692
698inline bool operator!=(const fd &a, const fd &b) {
699 return a._p != b._p;
700}
701
702
703inline fdref::fdref()
704 : imp_(0), flags_(0) {
705}
706
707inline fdref::fdref(const fd& f)
708 : imp_(f._p), flags_(0) {
709 if (imp_)
710 ++imp_->ref_count_;
711}
712
713inline fdref::fdref(fd&& f)
714 : imp_(f._p), flags_(0) {
715 f._p = 0;
716}
717
718inline fdref::fdref(const fd& f, ref_type ref)
719 : imp_(f._p), flags_(ref) {
720 if (imp_ && ref == weak)
721 ++imp_->weak_count_;
722 else if (imp_)
723 ++imp_->ref_count_;
724}
725
726inline fdref::fdref(fd&& f, ref_type ref)
727 : imp_(f._p), flags_(ref) {
728 f._p = 0;
729 if (imp_ && ref == weak) {
730 ++imp_->weak_count_;
731 imp_->deref();
732 }
733}
734
735inline fdref::~fdref() {
736 if (imp_ && (flags_ & read_locked))
737 imp_->rlock_.release();
738 if (imp_ && (flags_ & write_locked))
739 imp_->wlock_.release();
740 if (imp_ && (flags_ & weak))
741 imp_->weak_deref();
742 else if (imp_)
743 imp_->deref();
744}
745
746inline fdref::operator bool() const {
747 return imp_ && imp_->fde_ >= 0;
748}
749
750inline int fdref::fdnum() const {
751 assert(imp_ && imp_->fde_ >= 0);
752 return imp_->fdv_;
753}
754
755inline void fdref::acquire_read(event<> done) {
756 assert(!(flags_ & read_locked));
757 flags_ |= read_locked;
758 if (imp_)
759 imp_->rlock_.acquire(std::move(done));
760 else
761 done();
762}
763
764inline void fdref::release_read() {
765 assert(flags_ & read_locked);
766 flags_ &= ~read_locked;
767 if (imp_)
768 imp_->rlock_.release();
769}
770
771inline ssize_t fdref::read(void* buf, size_t size) {
772 assert(flags_ & read_locked);
773 if (imp_ && imp_->fde_ >= 0)
774 return ::read(imp_->fdv_, buf, size);
775 else {
776 errno = EBADF;
777 return -1;
778 }
779}
780
781inline void fdref::acquire_write(event<> done) {
782 assert(!(flags_ & write_locked));
783 flags_ |= write_locked;
784 if (imp_)
785 imp_->wlock_.acquire(std::move(done));
786 else
787 done();
788}
789
790inline void fdref::release_write() {
791 assert(flags_ & write_locked);
792 flags_ &= ~write_locked;
793 if (imp_)
794 imp_->wlock_.release();
795}
796
797inline ssize_t fdref::write(const void* buf, size_t size) {
798 assert(flags_ & write_locked);
799 if (imp_ && imp_->fde_ >= 0)
800 return ::write(imp_->fdv_, buf, size);
801 else {
802 errno = EBADF;
803 return -1;
804 }
805}
806
807inline void fdref::close() {
808 if (imp_)
809 imp_->close();
810}
811
812inline void fdref::close(int errcode) {
813 if (imp_)
814 imp_->close(errcode);
815}
816
817
828inline void tcp_listen(int port, int backlog, event<fd> result) {
829 result.trigger(tcp_listen(port, backlog));
830}
831
838inline void tcp_listen(int port, event<fd> result) {
839 tcp_listen(port, fd::default_backlog, result);
840}
841
848inline fd tcp_listen(int port) {
849 return tcp_listen(port, fd::default_backlog);
850}
851
852inline void tcp_connect(int port, event<fd> result) {
853 struct in_addr in;
854 in.s_addr = ntohl(INADDR_LOOPBACK);
855 tcp_connect(in, port, std::move(result));
856}
857
858inline fd unix_stream_listen(std::string path) {
859 return unix_stream_listen(std::move(path), fd::default_backlog);
860}
861
862inline exec_fd::exec_fd(int child_fd, fdtype type, fd f)
863 : child_fd(child_fd), type(type), f(f) {
864}
865
866inline pid_t execv(fd &in, fd &out, const char *program,
867 const std::vector<const char *> &argv) {
868 std::vector<exec_fd> efd;
869 efd.push_back(exec_fd(STDIN_FILENO, exec_fd::fdtype_newin));
870 efd.push_back(exec_fd(STDOUT_FILENO, exec_fd::fdtype_newout));
871 pid_t r = exec(efd, program, false, argv, 0);
872 in = efd[0].f;
873 out = efd[1].f;
874 return r;
875}
876
877inline pid_t execv(fd &in, fd &out, fd &err, const char *program,
878 const std::vector<const char *> &argv) {
879 std::vector<exec_fd> efd;
880 efd.push_back(exec_fd(STDIN_FILENO, exec_fd::fdtype_newin));
881 efd.push_back(exec_fd(STDOUT_FILENO, exec_fd::fdtype_newout));
882 efd.push_back(exec_fd(STDERR_FILENO, exec_fd::fdtype_newout));
883 pid_t r = exec(efd, program, false, argv, 0);
884 in = efd[0].f;
885 out = efd[1].f;
886 err = efd[2].f;
887 return r;
888}
889
890inline pid_t execvp(fd &in, fd &out, const char *program,
891 const std::vector<const char *> &argv) {
892 std::vector<exec_fd> efd;
893 efd.push_back(exec_fd(STDIN_FILENO, exec_fd::fdtype_newin));
894 efd.push_back(exec_fd(STDOUT_FILENO, exec_fd::fdtype_newout));
895 pid_t r = exec(efd, program, true, argv, 0);
896 in = efd[0].f;
897 out = efd[1].f;
898 return r;
899}
900
901inline pid_t execvp(fd &in, fd &out, fd &err, const char *program,
902 const std::vector<const char *> &argv) {
903 std::vector<exec_fd> efd;
904 efd.push_back(exec_fd(STDIN_FILENO, exec_fd::fdtype_newin));
905 efd.push_back(exec_fd(STDOUT_FILENO, exec_fd::fdtype_newout));
906 efd.push_back(exec_fd(STDERR_FILENO, exec_fd::fdtype_newout));
907 pid_t r = exec(efd, program, true, argv, 0);
908 in = efd[0].f;
909 out = efd[1].f;
910 err = efd[2].f;
911 return r;
912}
913
914} // namespace tamer
915#endif /* TAMER_FD_HH */
A future occurrence.
Definition event.hh:116
void trigger(T0 v0, T1 v1, T2 v2, T3 v3)
Trigger event.
Definition event.hh:742
Classes for event-based synchronization.
Namespace containing public Tamer classes and functions for the Tamer core.
Definition adapter.hh:17
fd tcp_listen(int port)
Open a nonblocking TCP connection on port port.
Definition fd.hh:848
bool operator!=(const fd &a, const fd &b)
Test whether two file descriptors refer to the same object.
Definition fd.hh:698
bool operator==(const fd &a, const fd &b)
Test whether two file descriptors refer to the same object.
Definition fd.hh:689
The main Tamer header file.