1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/serial/serial_io_handler_posix.h"
6
7 #include "base/posix/eintr_wrapper.h"
8
9 namespace {
10 const base::PlatformFile kInvalidPlatformFileValue = -1;
11 } // namespace
12
13 namespace extensions {
14
15 // static
Create()16 scoped_refptr<SerialIoHandler> SerialIoHandler::Create() {
17 return new SerialIoHandlerPosix();
18 }
19
ReadImpl()20 void SerialIoHandlerPosix::ReadImpl() {
21 DCHECK(CalledOnValidThread());
22 DCHECK(pending_read_buffer());
23 DCHECK_NE(file(), kInvalidPlatformFileValue);
24
25 EnsureWatchingReads();
26 }
27
WriteImpl()28 void SerialIoHandlerPosix::WriteImpl() {
29 DCHECK(CalledOnValidThread());
30 DCHECK(pending_write_buffer());
31 DCHECK_NE(file(), kInvalidPlatformFileValue);
32
33 EnsureWatchingWrites();
34 }
35
CancelReadImpl()36 void SerialIoHandlerPosix::CancelReadImpl() {
37 DCHECK(CalledOnValidThread());
38 is_watching_reads_ = false;
39 file_read_watcher_.StopWatchingFileDescriptor();
40 QueueReadCompleted(0, read_cancel_reason());
41 }
42
CancelWriteImpl()43 void SerialIoHandlerPosix::CancelWriteImpl() {
44 DCHECK(CalledOnValidThread());
45 is_watching_writes_ = false;
46 file_write_watcher_.StopWatchingFileDescriptor();
47 QueueWriteCompleted(0, write_cancel_reason());
48 }
49
SerialIoHandlerPosix()50 SerialIoHandlerPosix::SerialIoHandlerPosix()
51 : is_watching_reads_(false),
52 is_watching_writes_(false) {
53 }
54
~SerialIoHandlerPosix()55 SerialIoHandlerPosix::~SerialIoHandlerPosix() {}
56
OnFileCanReadWithoutBlocking(int fd)57 void SerialIoHandlerPosix::OnFileCanReadWithoutBlocking(int fd) {
58 DCHECK(CalledOnValidThread());
59 DCHECK_EQ(fd, file());
60
61 if (pending_read_buffer()) {
62 int bytes_read = HANDLE_EINTR(read(file(),
63 pending_read_buffer()->data(),
64 pending_read_buffer_len()));
65 if (bytes_read < 0) {
66 if (errno == ENXIO) {
67 ReadCompleted(0, api::serial::RECEIVE_ERROR_DEVICE_LOST);
68 } else {
69 ReadCompleted(0, api::serial::RECEIVE_ERROR_SYSTEM_ERROR);
70 }
71 } else if (bytes_read == 0) {
72 ReadCompleted(0, api::serial::RECEIVE_ERROR_DEVICE_LOST);
73 } else {
74 ReadCompleted(bytes_read, api::serial::RECEIVE_ERROR_NONE);
75 }
76 } else {
77 // Stop watching the fd if we get notifications with no pending
78 // reads or writes to avoid starving the message loop.
79 is_watching_reads_ = false;
80 file_read_watcher_.StopWatchingFileDescriptor();
81 }
82 }
83
OnFileCanWriteWithoutBlocking(int fd)84 void SerialIoHandlerPosix::OnFileCanWriteWithoutBlocking(int fd) {
85 DCHECK(CalledOnValidThread());
86 DCHECK_EQ(fd, file());
87
88 if (pending_write_buffer()) {
89 int bytes_written = HANDLE_EINTR(write(file(),
90 pending_write_buffer()->data(),
91 pending_write_buffer_len()));
92 if (bytes_written < 0) {
93 WriteCompleted(0, api::serial::SEND_ERROR_SYSTEM_ERROR);
94 } else {
95 WriteCompleted(bytes_written, api::serial::SEND_ERROR_NONE);
96 }
97 } else {
98 // Stop watching the fd if we get notifications with no pending
99 // writes to avoid starving the message loop.
100 is_watching_writes_ = false;
101 file_write_watcher_.StopWatchingFileDescriptor();
102 }
103 }
104
EnsureWatchingReads()105 void SerialIoHandlerPosix::EnsureWatchingReads() {
106 DCHECK(CalledOnValidThread());
107 DCHECK_NE(file(), kInvalidPlatformFileValue);
108 if (!is_watching_reads_) {
109 is_watching_reads_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
110 file(), true, base::MessageLoopForIO::WATCH_READ,
111 &file_read_watcher_, this);
112 }
113 }
114
EnsureWatchingWrites()115 void SerialIoHandlerPosix::EnsureWatchingWrites() {
116 DCHECK(CalledOnValidThread());
117 DCHECK_NE(file(), kInvalidPlatformFileValue);
118 if (!is_watching_writes_) {
119 is_watching_writes_ =
120 base::MessageLoopForIO::current()->WatchFileDescriptor(
121 file(), true, base::MessageLoopForIO::WATCH_WRITE,
122 &file_write_watcher_, this);
123 }
124 }
125
126 } // namespace extensions
127