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 9namespace extensions { 10 11// static 12scoped_refptr<SerialIoHandler> SerialIoHandler::Create() { 13 return new SerialIoHandlerPosix(); 14} 15 16void SerialIoHandlerPosix::ReadImpl() { 17 DCHECK(CalledOnValidThread()); 18 DCHECK(pending_read_buffer()); 19 DCHECK_NE(file(), base::kInvalidPlatformFileValue); 20 21 EnsureWatchingReads(); 22} 23 24void SerialIoHandlerPosix::WriteImpl() { 25 DCHECK(CalledOnValidThread()); 26 DCHECK(pending_write_buffer()); 27 DCHECK_NE(file(), base::kInvalidPlatformFileValue); 28 29 EnsureWatchingWrites(); 30} 31 32void SerialIoHandlerPosix::CancelReadImpl() { 33 DCHECK(CalledOnValidThread()); 34 is_watching_reads_ = false; 35 file_read_watcher_.StopWatchingFileDescriptor(); 36} 37 38void SerialIoHandlerPosix::CancelWriteImpl() { 39 DCHECK(CalledOnValidThread()); 40 is_watching_writes_ = false; 41 file_write_watcher_.StopWatchingFileDescriptor(); 42} 43 44SerialIoHandlerPosix::SerialIoHandlerPosix() 45 : is_watching_reads_(false), 46 is_watching_writes_(false) { 47} 48 49SerialIoHandlerPosix::~SerialIoHandlerPosix() {} 50 51void SerialIoHandlerPosix::OnFileCanReadWithoutBlocking(int fd) { 52 DCHECK(CalledOnValidThread()); 53 DCHECK_EQ(fd, file()); 54 55 if (pending_read_buffer()) { 56 int bytes_read = HANDLE_EINTR(read(file(), 57 pending_read_buffer()->data(), 58 pending_read_buffer_len())); 59 if (bytes_read < 0) { 60 if (errno == ENXIO) { 61 ReadCompleted(0, api::serial::RECEIVE_ERROR_DEVICE_LOST); 62 } else { 63 ReadCompleted(0, api::serial::RECEIVE_ERROR_SYSTEM_ERROR); 64 } 65 } else if (bytes_read == 0) { 66 ReadCompleted(0, api::serial::RECEIVE_ERROR_DEVICE_LOST); 67 } else { 68 ReadCompleted(bytes_read, api::serial::RECEIVE_ERROR_NONE); 69 } 70 } else { 71 // Stop watching the fd if we get notifications with no pending 72 // reads or writes to avoid starving the message loop. 73 is_watching_reads_ = false; 74 file_read_watcher_.StopWatchingFileDescriptor(); 75 } 76} 77 78void SerialIoHandlerPosix::OnFileCanWriteWithoutBlocking(int fd) { 79 DCHECK(CalledOnValidThread()); 80 DCHECK_EQ(fd, file()); 81 82 if (pending_write_buffer()) { 83 int bytes_written = HANDLE_EINTR(write(file(), 84 pending_write_buffer()->data(), 85 pending_write_buffer_len())); 86 if (bytes_written < 0) { 87 WriteCompleted(0, api::serial::SEND_ERROR_SYSTEM_ERROR); 88 } else { 89 WriteCompleted(bytes_written, api::serial::SEND_ERROR_NONE); 90 } 91 } else { 92 // Stop watching the fd if we get notifications with no pending 93 // writes to avoid starving the message loop. 94 is_watching_writes_ = false; 95 file_write_watcher_.StopWatchingFileDescriptor(); 96 } 97} 98 99void SerialIoHandlerPosix::EnsureWatchingReads() { 100 DCHECK(CalledOnValidThread()); 101 DCHECK_NE(file(), base::kInvalidPlatformFileValue); 102 if (!is_watching_reads_) { 103 is_watching_reads_ = base::MessageLoopForIO::current()->WatchFileDescriptor( 104 file(), true, base::MessageLoopForIO::WATCH_READ, 105 &file_read_watcher_, this); 106 } 107} 108 109void SerialIoHandlerPosix::EnsureWatchingWrites() { 110 DCHECK(CalledOnValidThread()); 111 DCHECK_NE(file(), base::kInvalidPlatformFileValue); 112 if (!is_watching_writes_) { 113 is_watching_writes_ = 114 base::MessageLoopForIO::current()->WatchFileDescriptor( 115 file(), true, base::MessageLoopForIO::WATCH_WRITE, 116 &file_write_watcher_, this); 117 } 118} 119 120} // namespace extensions 121