1 /* 2 * Copyright 2007-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "fifo.h" 9 10 #include <limits.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <sys/ioctl.h> 15 #include <sys/stat.h> 16 17 #include <new> 18 19 #include <KernelExport.h> 20 #include <NodeMonitor.h> 21 #include <Select.h> 22 23 #include <condition_variable.h> 24 #include <debug_hex_dump.h> 25 #include <lock.h> 26 #include <select_sync_pool.h> 27 #include <syscall_restart.h> 28 #include <team.h> 29 #include <thread.h> 30 #include <util/DoublyLinkedList.h> 31 #include <util/AutoLock.h> 32 #include <util/ring_buffer.h> 33 #include <vfs.h> 34 #include <vfs_defs.h> 35 #include <vm/vm.h> 36 37 38 //#define TRACE_FIFO 39 #ifdef TRACE_FIFO 40 # define TRACE(x...) dprintf(x) 41 #else 42 # define TRACE(x...) 43 #endif 44 45 46 namespace fifo { 47 48 49 struct file_cookie; 50 class Inode; 51 52 53 class RingBuffer { 54 public: 55 RingBuffer(); 56 ~RingBuffer(); 57 58 status_t CreateBuffer(); 59 void DeleteBuffer(); 60 61 ssize_t Write(const void* buffer, size_t length, 62 bool isUser); 63 ssize_t Read(void* buffer, size_t length, bool isUser); 64 ssize_t Peek(size_t offset, void* buffer, 65 size_t length) const; 66 67 size_t Readable() const; 68 size_t Writable() const; 69 70 private: 71 struct ring_buffer* fBuffer; 72 }; 73 74 75 class ReadRequest : public DoublyLinkedListLinkImpl<ReadRequest> { 76 public: 77 ReadRequest(file_cookie* cookie) 78 : 79 fThread(thread_get_current_thread()), 80 fCookie(cookie), 81 fNotified(true) 82 { 83 B_INITIALIZE_SPINLOCK(&fLock); 84 } 85 86 void SetNotified(bool notified) 87 { 88 InterruptsSpinLocker _(fLock); 89 fNotified = notified; 90 } 91 92 void Notify(status_t status = B_OK) 93 { 94 InterruptsSpinLocker _(fLock); 95 TRACE("ReadRequest %p::Notify(), fNotified %d\n", this, fNotified); 96 97 if (!fNotified) { 98 thread_unblock(fThread, status); 99 fNotified = true; 100 } 101 } 102 103 Thread* GetThread() const 104 { 105 return fThread; 106 } 107 108 file_cookie* Cookie() const 109 { 110 return fCookie; 111 } 112 113 private: 114 spinlock fLock; 115 Thread* fThread; 116 file_cookie* fCookie; 117 volatile bool fNotified; 118 }; 119 120 121 class WriteRequest : public DoublyLinkedListLinkImpl<WriteRequest> { 122 public: 123 WriteRequest(Thread* thread, size_t minimalWriteCount) 124 : 125 fThread(thread), 126 fMinimalWriteCount(minimalWriteCount) 127 { 128 } 129 130 Thread* GetThread() const 131 { 132 return fThread; 133 } 134 135 size_t MinimalWriteCount() const 136 { 137 return fMinimalWriteCount; 138 } 139 140 private: 141 Thread* fThread; 142 size_t fMinimalWriteCount; 143 }; 144 145 146 typedef DoublyLinkedList<ReadRequest> ReadRequestList; 147 typedef DoublyLinkedList<WriteRequest> WriteRequestList; 148 149 150 class Inode { 151 public: 152 Inode(); 153 ~Inode(); 154 155 status_t InitCheck(); 156 157 bool IsActive() const { return fActive; } 158 timespec CreationTime() const { return fCreationTime; } 159 void SetCreationTime(timespec creationTime) 160 { fCreationTime = creationTime; } 161 timespec ModificationTime() const 162 { return fModificationTime; } 163 void SetModificationTime(timespec modificationTime) 164 { fModificationTime = modificationTime; } 165 166 mutex* RequestLock() { return &fRequestLock; } 167 168 status_t WriteDataToBuffer(const void* data, 169 size_t* _length, bool nonBlocking, 170 bool isUser); 171 status_t ReadDataFromBuffer(void* data, size_t* _length, 172 bool nonBlocking, bool isUser, 173 ReadRequest& request); 174 size_t BytesAvailable() const 175 { return fBuffer.Readable(); } 176 size_t BytesWritable() const 177 { return fBuffer.Writable(); } 178 179 void AddReadRequest(ReadRequest& request); 180 void RemoveReadRequest(ReadRequest& request); 181 status_t WaitForReadRequest(ReadRequest& request); 182 183 void NotifyBytesRead(size_t bytes); 184 void NotifyReadDone(); 185 void NotifyBytesWritten(size_t bytes); 186 void NotifyEndClosed(bool writer); 187 188 status_t Open(int openMode); 189 void Close(file_cookie* cookie); 190 int32 ReaderCount() const { return fReaderCount; } 191 int32 WriterCount() const { return fWriterCount; } 192 193 status_t Select(uint8 event, selectsync* sync, 194 int openMode); 195 status_t Deselect(uint8 event, selectsync* sync, 196 int openMode); 197 198 void Dump(bool dumpData) const; 199 static int Dump(int argc, char** argv); 200 201 private: 202 timespec fCreationTime; 203 timespec fModificationTime; 204 205 RingBuffer fBuffer; 206 207 ReadRequestList fReadRequests; 208 WriteRequestList fWriteRequests; 209 210 mutex fRequestLock; 211 212 ConditionVariable fActiveCondition; 213 214 int32 fReaderCount; 215 int32 fWriterCount; 216 bool fActive; 217 218 select_sync_pool* fReadSelectSyncPool; 219 select_sync_pool* fWriteSelectSyncPool; 220 }; 221 222 223 class FIFOInode : public Inode { 224 public: 225 FIFOInode(fs_vnode* vnode) 226 : 227 Inode(), 228 fSuperVnode(*vnode) 229 { 230 } 231 232 fs_vnode* SuperVnode() { return &fSuperVnode; } 233 234 private: 235 fs_vnode fSuperVnode; 236 }; 237 238 239 struct file_cookie { 240 int open_mode; 241 // guarded by Inode::fRequestLock 242 243 void SetNonBlocking(bool nonBlocking) 244 { 245 if (nonBlocking) 246 open_mode |= O_NONBLOCK; 247 else 248 open_mode &= ~(int)O_NONBLOCK; 249 } 250 }; 251 252 253 // #pragma mark - 254 255 256 RingBuffer::RingBuffer() 257 : 258 fBuffer(NULL) 259 { 260 } 261 262 263 RingBuffer::~RingBuffer() 264 { 265 DeleteBuffer(); 266 } 267 268 269 status_t 270 RingBuffer::CreateBuffer() 271 { 272 if (fBuffer != NULL) 273 return B_OK; 274 275 fBuffer = create_ring_buffer(VFS_FIFO_BUFFER_CAPACITY); 276 return fBuffer != NULL ? B_OK : B_NO_MEMORY; 277 } 278 279 280 void 281 RingBuffer::DeleteBuffer() 282 { 283 if (fBuffer != NULL) { 284 delete_ring_buffer(fBuffer); 285 fBuffer = NULL; 286 } 287 } 288 289 290 inline ssize_t 291 RingBuffer::Write(const void* buffer, size_t length, bool isUser) 292 { 293 if (fBuffer == NULL) 294 return B_NO_MEMORY; 295 if (isUser && !IS_USER_ADDRESS(buffer)) 296 return B_BAD_ADDRESS; 297 298 return isUser 299 ? ring_buffer_user_write(fBuffer, (const uint8*)buffer, length) 300 : ring_buffer_write(fBuffer, (const uint8*)buffer, length); 301 } 302 303 304 inline ssize_t 305 RingBuffer::Read(void* buffer, size_t length, bool isUser) 306 { 307 if (fBuffer == NULL) 308 return B_NO_MEMORY; 309 if (isUser && !IS_USER_ADDRESS(buffer)) 310 return B_BAD_ADDRESS; 311 312 return isUser 313 ? ring_buffer_user_read(fBuffer, (uint8*)buffer, length) 314 : ring_buffer_read(fBuffer, (uint8*)buffer, length); 315 } 316 317 318 inline ssize_t 319 RingBuffer::Peek(size_t offset, void* buffer, size_t length) const 320 { 321 if (fBuffer == NULL) 322 return B_NO_MEMORY; 323 324 return ring_buffer_peek(fBuffer, offset, (uint8*)buffer, length); 325 } 326 327 328 inline size_t 329 RingBuffer::Readable() const 330 { 331 return fBuffer != NULL ? ring_buffer_readable(fBuffer) : 0; 332 } 333 334 335 inline size_t 336 RingBuffer::Writable() const 337 { 338 return fBuffer != NULL ? ring_buffer_writable(fBuffer) : 0; 339 } 340 341 342 // #pragma mark - 343 344 345 Inode::Inode() 346 : 347 fReadRequests(), 348 fWriteRequests(), 349 fReaderCount(0), 350 fWriterCount(0), 351 fActive(false), 352 fReadSelectSyncPool(NULL), 353 fWriteSelectSyncPool(NULL) 354 { 355 fActiveCondition.Publish(this, "pipe"); 356 mutex_init(&fRequestLock, "pipe request"); 357 358 bigtime_t time = real_time_clock(); 359 fModificationTime.tv_sec = time / 1000000; 360 fModificationTime.tv_nsec = (time % 1000000) * 1000; 361 fCreationTime = fModificationTime; 362 } 363 364 365 Inode::~Inode() 366 { 367 fActiveCondition.Unpublish(); 368 mutex_destroy(&fRequestLock); 369 } 370 371 372 status_t 373 Inode::InitCheck() 374 { 375 return B_OK; 376 } 377 378 379 /*! Writes the specified data bytes to the inode's ring buffer. The 380 request lock must be held when calling this method. 381 Notifies readers if necessary, so that blocking readers will get started. 382 Returns B_OK for success, B_BAD_ADDRESS if copying from the buffer failed, 383 and various semaphore errors (like B_WOULD_BLOCK in non-blocking mode). If 384 the returned length is > 0, the returned error code can be ignored. 385 */ 386 status_t 387 Inode::WriteDataToBuffer(const void* _data, size_t* _length, bool nonBlocking, 388 bool isUser) 389 { 390 const uint8* data = (const uint8*)_data; 391 size_t dataSize = *_length; 392 size_t& written = *_length; 393 written = 0; 394 395 TRACE("Inode %p::WriteDataToBuffer(data = %p, bytes = %zu)\n", this, data, 396 dataSize); 397 398 // A request up to VFS_FIFO_ATOMIC_WRITE_SIZE bytes shall not be 399 // interleaved with other writer's data. 400 size_t minToWrite = 1; 401 if (dataSize <= VFS_FIFO_ATOMIC_WRITE_SIZE) 402 minToWrite = dataSize; 403 404 while (dataSize > 0) { 405 // Wait until enough space in the buffer is available. 406 while (!fActive 407 || (fBuffer.Writable() < minToWrite && fReaderCount > 0)) { 408 if (nonBlocking) 409 return B_WOULD_BLOCK; 410 411 ConditionVariableEntry entry; 412 entry.Add(this); 413 414 WriteRequest request(thread_get_current_thread(), minToWrite); 415 fWriteRequests.Add(&request); 416 417 mutex_unlock(&fRequestLock); 418 status_t status = entry.Wait(B_CAN_INTERRUPT); 419 mutex_lock(&fRequestLock); 420 421 fWriteRequests.Remove(&request); 422 423 if (status != B_OK) 424 return status; 425 } 426 427 // write only as long as there are readers left 428 if (fActive && fReaderCount == 0) { 429 if (written == 0) 430 send_signal(find_thread(NULL), SIGPIPE); 431 return EPIPE; 432 } 433 434 // write as much as we can 435 436 size_t toWrite = (fActive ? fBuffer.Writable() : 0); 437 if (toWrite > dataSize) 438 toWrite = dataSize; 439 440 if (toWrite > 0) { 441 ssize_t bytesWritten = fBuffer.Write(data, toWrite, isUser); 442 if (bytesWritten < 0) 443 return bytesWritten; 444 } 445 446 data += toWrite; 447 dataSize -= toWrite; 448 written += toWrite; 449 450 NotifyBytesWritten(toWrite); 451 } 452 453 return B_OK; 454 } 455 456 457 status_t 458 Inode::ReadDataFromBuffer(void* data, size_t* _length, bool nonBlocking, 459 bool isUser, ReadRequest& request) 460 { 461 size_t dataSize = *_length; 462 *_length = 0; 463 464 // wait until our request is first in queue 465 status_t error; 466 if (fReadRequests.Head() != &request) { 467 if (nonBlocking) 468 return B_WOULD_BLOCK; 469 470 TRACE("Inode %p::%s(): wait for request %p to become the first " 471 "request.\n", this, __FUNCTION__, &request); 472 473 error = WaitForReadRequest(request); 474 if (error != B_OK) 475 return error; 476 } 477 478 // wait until data are available 479 while (fBuffer.Readable() == 0) { 480 if (nonBlocking) 481 return B_WOULD_BLOCK; 482 483 if (fActive && fWriterCount == 0) 484 return B_OK; 485 486 TRACE("Inode %p::%s(): wait for data, request %p\n", this, __FUNCTION__, 487 &request); 488 489 error = WaitForReadRequest(request); 490 if (error != B_OK) 491 return error; 492 } 493 494 // read as much as we can 495 size_t toRead = fBuffer.Readable(); 496 if (toRead > dataSize) 497 toRead = dataSize; 498 499 ssize_t bytesRead = fBuffer.Read(data, toRead, isUser); 500 if (bytesRead < 0) 501 return bytesRead; 502 503 NotifyBytesRead(toRead); 504 505 *_length = toRead; 506 507 return B_OK; 508 } 509 510 511 void 512 Inode::AddReadRequest(ReadRequest& request) 513 { 514 fReadRequests.Add(&request); 515 } 516 517 518 void 519 Inode::RemoveReadRequest(ReadRequest& request) 520 { 521 fReadRequests.Remove(&request); 522 } 523 524 525 status_t 526 Inode::WaitForReadRequest(ReadRequest& request) 527 { 528 // add the entry to wait on 529 thread_prepare_to_block(thread_get_current_thread(), B_CAN_INTERRUPT, 530 THREAD_BLOCK_TYPE_OTHER, "fifo read request"); 531 532 request.SetNotified(false); 533 534 // wait 535 mutex_unlock(&fRequestLock); 536 status_t status = thread_block(); 537 538 // Before going to lock again, we need to make sure no one tries to 539 // unblock us. Otherwise that would screw with mutex_lock(). 540 request.SetNotified(true); 541 542 mutex_lock(&fRequestLock); 543 544 return status; 545 } 546 547 548 void 549 Inode::NotifyBytesRead(size_t bytes) 550 { 551 // notify writer, if something can be written now 552 size_t writable = fBuffer.Writable(); 553 if (bytes > 0) { 554 // notify select()ors only, if nothing was writable before 555 if (writable == bytes) { 556 if (fWriteSelectSyncPool) 557 notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE); 558 } 559 560 // If any of the waiting writers has a minimal write count that has 561 // now become satisfied, we notify all of them (condition variables 562 // don't support doing that selectively). 563 WriteRequest* request; 564 WriteRequestList::Iterator iterator = fWriteRequests.GetIterator(); 565 while ((request = iterator.Next()) != NULL) { 566 size_t minWriteCount = request->MinimalWriteCount(); 567 if (minWriteCount > 0 && minWriteCount <= writable 568 && minWriteCount > writable - bytes) { 569 fActiveCondition.NotifyAll(); 570 break; 571 } 572 } 573 } 574 } 575 576 577 void 578 Inode::NotifyReadDone() 579 { 580 // notify next reader, if there's still something to be read 581 if (fBuffer.Readable() > 0) { 582 if (ReadRequest* request = fReadRequests.First()) 583 request->Notify(); 584 } 585 } 586 587 588 void 589 Inode::NotifyBytesWritten(size_t bytes) 590 { 591 // notify reader, if something can be read now 592 if (bytes > 0 && fBuffer.Readable() == bytes) { 593 if (fReadSelectSyncPool) 594 notify_select_event_pool(fReadSelectSyncPool, B_SELECT_READ); 595 596 if (ReadRequest* request = fReadRequests.First()) 597 request->Notify(); 598 } 599 } 600 601 602 void 603 Inode::NotifyEndClosed(bool writer) 604 { 605 TRACE("Inode %p::%s(%s)\n", this, __FUNCTION__, 606 writer ? "writer" : "reader"); 607 608 if (writer) { 609 // Our last writer has been closed; if the pipe 610 // contains no data, unlock all waiting readers 611 TRACE(" buffer readable: %zu\n", fBuffer.Readable()); 612 if (fBuffer.Readable() == 0) { 613 ReadRequestList::Iterator iterator = fReadRequests.GetIterator(); 614 while (ReadRequest* request = iterator.Next()) 615 request->Notify(); 616 617 if (fReadSelectSyncPool) 618 notify_select_event_pool(fReadSelectSyncPool, B_SELECT_DISCONNECTED); 619 620 } 621 } else { 622 // Last reader is gone. Wake up all writers. 623 fActiveCondition.NotifyAll(); 624 625 if (fWriteSelectSyncPool) 626 notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_ERROR); 627 } 628 } 629 630 631 status_t 632 Inode::Open(int openMode) 633 { 634 MutexLocker locker(RequestLock()); 635 636 if ((openMode & O_ACCMODE) == O_WRONLY || (openMode & O_ACCMODE) == O_RDWR) 637 fWriterCount++; 638 639 if ((openMode & O_ACCMODE) == O_RDONLY || (openMode & O_ACCMODE) == O_RDWR) 640 fReaderCount++; 641 642 bool shouldWait = false; 643 if ((openMode & O_ACCMODE) == O_WRONLY && fReaderCount == 0) { 644 if ((openMode & O_NONBLOCK) != 0) 645 return ENXIO; 646 shouldWait = true; 647 } 648 if ((openMode & O_ACCMODE) == O_RDONLY && fWriterCount == 0 649 && (openMode & O_NONBLOCK) == 0) { 650 shouldWait = true; 651 } 652 if (shouldWait) { 653 // prepare for waiting for the condition variable. 654 ConditionVariableEntry waitEntry; 655 fActiveCondition.Add(&waitEntry); 656 locker.Unlock(); 657 status_t status = waitEntry.Wait(B_CAN_INTERRUPT); 658 if (status != B_OK) 659 return status; 660 locker.Lock(); 661 } 662 663 if (fReaderCount > 0 && fWriterCount > 0) { 664 TRACE("Inode %p::Open(): fifo becomes active\n", this); 665 fBuffer.CreateBuffer(); 666 fActive = true; 667 668 // notify all waiting writers that they can start 669 if (fWriteSelectSyncPool) 670 notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE); 671 fActiveCondition.NotifyAll(); 672 } 673 return B_OK; 674 } 675 676 677 void 678 Inode::Close(file_cookie* cookie) 679 { 680 681 MutexLocker locker(RequestLock()); 682 683 int openMode = cookie->open_mode; 684 TRACE("Inode %p::Close(openMode = %" B_PRId32 ")\n", this, openMode); 685 686 // Notify all currently reading file descriptors 687 ReadRequestList::Iterator iterator = fReadRequests.GetIterator(); 688 while (ReadRequest* request = iterator.Next()) { 689 if (request->Cookie() == cookie) 690 request->Notify(B_FILE_ERROR); 691 } 692 693 if ((openMode & O_ACCMODE) == O_WRONLY || (openMode & O_ACCMODE) == O_RDWR) { 694 if (--fWriterCount == 0) 695 NotifyEndClosed(true); 696 } 697 698 if ((openMode & O_ACCMODE) == O_RDONLY || (openMode & O_ACCMODE) == O_RDWR) { 699 if (--fReaderCount == 0) 700 NotifyEndClosed(false); 701 } 702 703 if (fWriterCount == 0) { 704 // Notify any still reading writers to stop 705 // TODO: This only works reliable if there is only one writer - we could 706 // do the same thing done for the read requests. 707 fActiveCondition.NotifyAll(B_FILE_ERROR); 708 } 709 710 if (fReaderCount == 0 && fWriterCount == 0) { 711 fActive = false; 712 fBuffer.DeleteBuffer(); 713 } 714 } 715 716 717 status_t 718 Inode::Select(uint8 event, selectsync* sync, int openMode) 719 { 720 bool writer = true; 721 select_sync_pool** pool; 722 // B_SELECT_READ can happen on write-only opened fds, so restrain B_SELECT_READ to O_RDWR 723 if ((event == B_SELECT_READ && (openMode & O_RWMASK) == O_RDWR) 724 || (openMode & O_RWMASK) == O_RDONLY) { 725 pool = &fReadSelectSyncPool; 726 writer = false; 727 } else if ((openMode & O_RWMASK) == O_RDWR || (openMode & O_RWMASK) == O_WRONLY) { 728 pool = &fWriteSelectSyncPool; 729 } else 730 return B_NOT_ALLOWED; 731 732 if (add_select_sync_pool_entry(pool, sync, event) != B_OK) 733 return B_ERROR; 734 735 // signal right away, if the condition holds already 736 if (writer) { 737 if ((event == B_SELECT_WRITE && fBuffer.Writable() > 0) 738 || (event == B_SELECT_ERROR && fReaderCount == 0)) { 739 return notify_select_event(sync, event); 740 } 741 } else { 742 if ((event == B_SELECT_READ && fBuffer.Readable() > 0) 743 || (event == B_SELECT_DISCONNECTED && fWriterCount == 0)) { 744 return notify_select_event(sync, event); 745 } 746 } 747 748 return B_OK; 749 } 750 751 752 status_t 753 Inode::Deselect(uint8 event, selectsync* sync, int openMode) 754 { 755 select_sync_pool** pool; 756 if ((event == B_SELECT_READ && (openMode & O_RWMASK) == O_RDWR) 757 || (openMode & O_RWMASK) == O_RDONLY) { 758 pool = &fReadSelectSyncPool; 759 } else if ((openMode & O_RWMASK) == O_RDWR || (openMode & O_RWMASK) == O_WRONLY) { 760 pool = &fWriteSelectSyncPool; 761 } else 762 return B_NOT_ALLOWED; 763 764 remove_select_sync_pool_entry(pool, sync, event); 765 return B_OK; 766 } 767 768 769 void 770 Inode::Dump(bool dumpData) const 771 { 772 kprintf("FIFO %p\n", this); 773 kprintf(" active: %s\n", fActive ? "true" : "false"); 774 kprintf(" readers: %" B_PRId32 "\n", fReaderCount); 775 kprintf(" writers: %" B_PRId32 "\n", fWriterCount); 776 777 if (!fReadRequests.IsEmpty()) { 778 kprintf(" pending readers:\n"); 779 for (ReadRequestList::ConstIterator it = fReadRequests.GetIterator(); 780 ReadRequest* request = it.Next();) { 781 kprintf(" %p: thread %" B_PRId32 ", cookie: %p\n", request, 782 request->GetThread()->id, request->Cookie()); 783 } 784 } 785 786 if (!fWriteRequests.IsEmpty()) { 787 kprintf(" pending writers:\n"); 788 for (WriteRequestList::ConstIterator it = fWriteRequests.GetIterator(); 789 WriteRequest* request = it.Next();) { 790 kprintf(" %p: thread %" B_PRId32 ", min count: %zu\n", request, 791 request->GetThread()->id, request->MinimalWriteCount()); 792 } 793 } 794 795 kprintf(" %zu bytes buffered\n", fBuffer.Readable()); 796 797 if (dumpData && fBuffer.Readable() > 0) { 798 struct DataProvider : BKernel::HexDumpDataProvider { 799 DataProvider(const RingBuffer& buffer) 800 : 801 fBuffer(buffer), 802 fOffset(0) 803 { 804 } 805 806 virtual bool HasMoreData() const 807 { 808 return fOffset < fBuffer.Readable(); 809 } 810 811 virtual uint8 NextByte() 812 { 813 uint8 byte = '\0'; 814 if (fOffset < fBuffer.Readable()) { 815 fBuffer.Peek(fOffset, &byte, 1); 816 fOffset++; 817 } 818 return byte; 819 } 820 821 virtual bool GetAddressString(char* buffer, size_t bufferSize) const 822 { 823 snprintf(buffer, bufferSize, " %4zx", fOffset); 824 return true; 825 } 826 827 private: 828 const RingBuffer& fBuffer; 829 size_t fOffset; 830 }; 831 832 DataProvider dataProvider(fBuffer); 833 BKernel::print_hex_dump(dataProvider, fBuffer.Readable()); 834 } 835 } 836 837 838 /*static*/ int 839 Inode::Dump(int argc, char** argv) 840 { 841 bool dumpData = false; 842 int argi = 1; 843 if (argi < argc && strcmp(argv[argi], "-d") == 0) { 844 dumpData = true; 845 argi++; 846 } 847 848 if (argi >= argc || argi + 2 < argc) { 849 print_debugger_command_usage(argv[0]); 850 return 0; 851 } 852 853 Inode* node = (Inode*)parse_expression(argv[argi]); 854 if (IS_USER_ADDRESS(node)) { 855 kprintf("invalid FIFO address\n"); 856 return 0; 857 } 858 859 node->Dump(dumpData); 860 return 0; 861 } 862 863 864 // #pragma mark - vnode API 865 866 867 static status_t 868 fifo_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 869 { 870 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 871 fs_vnode* superVnode = fifo->SuperVnode(); 872 873 status_t error = B_OK; 874 if (superVnode->ops->put_vnode != NULL) 875 error = superVnode->ops->put_vnode(volume, superVnode, reenter); 876 877 delete fifo; 878 879 return error; 880 } 881 882 883 static status_t 884 fifo_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 885 { 886 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 887 fs_vnode* superVnode = fifo->SuperVnode(); 888 889 status_t error = B_OK; 890 if (superVnode->ops->remove_vnode != NULL) 891 error = superVnode->ops->remove_vnode(volume, superVnode, reenter); 892 893 delete fifo; 894 895 return error; 896 } 897 898 899 static status_t 900 fifo_open(fs_volume* _volume, fs_vnode* _node, int openMode, 901 void** _cookie) 902 { 903 Inode* inode = (Inode*)_node->private_node; 904 905 TRACE("fifo_open(): node = %p, openMode = %d\n", inode, openMode); 906 907 file_cookie* cookie = (file_cookie*)malloc(sizeof(file_cookie)); 908 if (cookie == NULL) 909 return B_NO_MEMORY; 910 911 TRACE(" open cookie = %p\n", cookie); 912 cookie->open_mode = openMode; 913 status_t status = inode->Open(openMode); 914 if (status != B_OK) { 915 free(cookie); 916 return status; 917 } 918 919 *_cookie = (void*)cookie; 920 921 return B_OK; 922 } 923 924 925 static status_t 926 fifo_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) 927 { 928 file_cookie* cookie = (file_cookie*)_cookie; 929 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 930 931 fifo->Close(cookie); 932 933 return B_OK; 934 } 935 936 937 static status_t 938 fifo_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) 939 { 940 file_cookie* cookie = (file_cookie*)_cookie; 941 942 TRACE("fifo_freecookie: entry vnode %p, cookie %p\n", _node, _cookie); 943 944 free(cookie); 945 946 return B_OK; 947 } 948 949 950 static status_t 951 fifo_fsync(fs_volume* _volume, fs_vnode* _node) 952 { 953 return B_BAD_VALUE; 954 } 955 956 957 static status_t 958 fifo_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, 959 off_t /*pos*/, void* buffer, size_t* _length) 960 { 961 file_cookie* cookie = (file_cookie*)_cookie; 962 Inode* inode = (Inode*)_node->private_node; 963 964 TRACE("fifo_read(vnode = %p, cookie = %p, length = %lu, mode = %d)\n", 965 inode, cookie, *_length, cookie->open_mode); 966 967 MutexLocker locker(inode->RequestLock()); 968 969 if (inode->IsActive() && inode->WriterCount() == 0) { 970 // as long there is no writer, and the pipe is empty, 971 // we always just return 0 to indicate end of file 972 if (inode->BytesAvailable() == 0) { 973 *_length = 0; 974 return B_OK; 975 } 976 } 977 978 // issue read request 979 980 ReadRequest request(cookie); 981 inode->AddReadRequest(request); 982 983 TRACE(" issue read request %p\n", &request); 984 985 size_t length = *_length; 986 status_t status = inode->ReadDataFromBuffer(buffer, &length, 987 (cookie->open_mode & O_NONBLOCK) != 0, is_called_via_syscall(), 988 request); 989 990 inode->RemoveReadRequest(request); 991 inode->NotifyReadDone(); 992 993 TRACE(" done reading request %p, length %zu\n", &request, length); 994 995 if (length > 0) 996 status = B_OK; 997 998 *_length = length; 999 return status; 1000 } 1001 1002 1003 static status_t 1004 fifo_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, 1005 off_t /*pos*/, const void* buffer, size_t* _length) 1006 { 1007 file_cookie* cookie = (file_cookie*)_cookie; 1008 Inode* inode = (Inode*)_node->private_node; 1009 1010 TRACE("fifo_write(vnode = %p, cookie = %p, length = %lu)\n", 1011 _node, cookie, *_length); 1012 1013 MutexLocker locker(inode->RequestLock()); 1014 1015 size_t length = *_length; 1016 if (length == 0) 1017 return B_OK; 1018 1019 // copy data into ring buffer 1020 status_t status = inode->WriteDataToBuffer(buffer, &length, 1021 (cookie->open_mode & O_NONBLOCK) != 0, is_called_via_syscall()); 1022 1023 if (length > 0) 1024 status = B_OK; 1025 1026 *_length = length; 1027 return status; 1028 } 1029 1030 1031 static status_t 1032 fifo_read_stat(fs_volume* volume, fs_vnode* vnode, struct ::stat* st) 1033 { 1034 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 1035 fs_vnode* superVnode = fifo->SuperVnode(); 1036 1037 if (superVnode->ops->read_stat == NULL) 1038 return B_BAD_VALUE; 1039 1040 status_t error = superVnode->ops->read_stat(volume, superVnode, st); 1041 if (error != B_OK) 1042 return error; 1043 1044 1045 MutexLocker locker(fifo->RequestLock()); 1046 1047 st->st_size = fifo->BytesAvailable(); 1048 1049 st->st_blksize = 4096; 1050 1051 // TODO: Just pass the changes to our modification time on to the super node. 1052 st->st_atim.tv_sec = time(NULL); 1053 st->st_atim.tv_nsec = 0; 1054 st->st_mtim = st->st_ctim = fifo->ModificationTime(); 1055 1056 return B_OK; 1057 } 1058 1059 1060 static status_t 1061 fifo_write_stat(fs_volume* volume, fs_vnode* vnode, const struct ::stat* st, 1062 uint32 statMask) 1063 { 1064 // we cannot change the size of anything 1065 if ((statMask & B_STAT_SIZE) != 0) 1066 return B_BAD_VALUE; 1067 1068 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 1069 fs_vnode* superVnode = fifo->SuperVnode(); 1070 1071 if (superVnode->ops->write_stat == NULL) 1072 return B_BAD_VALUE; 1073 1074 status_t error = superVnode->ops->write_stat(volume, superVnode, st, 1075 statMask); 1076 if (error != B_OK) 1077 return error; 1078 1079 return B_OK; 1080 } 1081 1082 1083 static status_t 1084 fifo_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 op, 1085 void* buffer, size_t length) 1086 { 1087 file_cookie* cookie = (file_cookie*)_cookie; 1088 Inode* inode = (Inode*)_node->private_node; 1089 1090 TRACE("fifo_ioctl: vnode %p, cookie %p, op %" B_PRId32 ", buf %p, len %ld\n", 1091 _node, _cookie, op, buffer, length); 1092 1093 switch (op) { 1094 case FIONREAD: 1095 { 1096 if (buffer == NULL) 1097 return B_BAD_VALUE; 1098 1099 MutexLocker locker(inode->RequestLock()); 1100 int available = (int)inode->BytesAvailable(); 1101 locker.Unlock(); 1102 1103 if (is_called_via_syscall()) { 1104 if (!IS_USER_ADDRESS(buffer) 1105 || user_memcpy(buffer, &available, sizeof(available)) 1106 != B_OK) { 1107 return B_BAD_ADDRESS; 1108 } 1109 } else 1110 *(int*)buffer = available; 1111 1112 return B_OK; 1113 } 1114 1115 case B_SET_BLOCKING_IO: 1116 case B_SET_NONBLOCKING_IO: 1117 { 1118 MutexLocker locker(inode->RequestLock()); 1119 cookie->SetNonBlocking(op == B_SET_NONBLOCKING_IO); 1120 return B_OK; 1121 } 1122 } 1123 1124 return EINVAL; 1125 } 1126 1127 1128 static status_t 1129 fifo_set_flags(fs_volume* _volume, fs_vnode* _node, void* _cookie, 1130 int flags) 1131 { 1132 Inode* inode = (Inode*)_node->private_node; 1133 file_cookie* cookie = (file_cookie*)_cookie; 1134 1135 TRACE("fifo_set_flags(vnode = %p, flags = %x)\n", _node, flags); 1136 1137 MutexLocker locker(inode->RequestLock()); 1138 cookie->open_mode = (cookie->open_mode & ~(O_APPEND | O_NONBLOCK)) | flags; 1139 return B_OK; 1140 } 1141 1142 1143 static status_t 1144 fifo_select(fs_volume* _volume, fs_vnode* _node, void* _cookie, 1145 uint8 event, selectsync* sync) 1146 { 1147 file_cookie* cookie = (file_cookie*)_cookie; 1148 1149 TRACE("fifo_select(vnode = %p)\n", _node); 1150 Inode* inode = (Inode*)_node->private_node; 1151 if (!inode) 1152 return B_ERROR; 1153 1154 MutexLocker locker(inode->RequestLock()); 1155 return inode->Select(event, sync, cookie->open_mode); 1156 } 1157 1158 1159 static status_t 1160 fifo_deselect(fs_volume* _volume, fs_vnode* _node, void* _cookie, 1161 uint8 event, selectsync* sync) 1162 { 1163 file_cookie* cookie = (file_cookie*)_cookie; 1164 1165 TRACE("fifo_deselect(vnode = %p)\n", _node); 1166 Inode* inode = (Inode*)_node->private_node; 1167 if (inode == NULL) 1168 return B_ERROR; 1169 1170 MutexLocker locker(inode->RequestLock()); 1171 return inode->Deselect(event, sync, cookie->open_mode); 1172 } 1173 1174 1175 static bool 1176 fifo_can_page(fs_volume* _volume, fs_vnode* _node, void* cookie) 1177 { 1178 return false; 1179 } 1180 1181 1182 static status_t 1183 fifo_read_pages(fs_volume* _volume, fs_vnode* _node, void* cookie, off_t pos, 1184 const iovec* vecs, size_t count, size_t* _numBytes) 1185 { 1186 return B_NOT_ALLOWED; 1187 } 1188 1189 1190 static status_t 1191 fifo_write_pages(fs_volume* _volume, fs_vnode* _node, void* cookie, 1192 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 1193 { 1194 return B_NOT_ALLOWED; 1195 } 1196 1197 1198 static status_t 1199 fifo_get_super_vnode(fs_volume* volume, fs_vnode* vnode, fs_volume* superVolume, 1200 fs_vnode* _superVnode) 1201 { 1202 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 1203 fs_vnode* superVnode = fifo->SuperVnode(); 1204 1205 if (superVnode->ops->get_super_vnode != NULL) { 1206 return superVnode->ops->get_super_vnode(volume, superVnode, superVolume, 1207 _superVnode); 1208 } 1209 1210 *_superVnode = *superVnode; 1211 1212 return B_OK; 1213 } 1214 1215 1216 static fs_vnode_ops sFIFOVnodeOps = { 1217 NULL, // lookup 1218 NULL, // get_vnode_name 1219 // TODO: This is suboptimal! We'd need to forward the 1220 // super node's hook, if it has got one. 1221 1222 &fifo_put_vnode, 1223 &fifo_remove_vnode, 1224 1225 &fifo_can_page, 1226 &fifo_read_pages, 1227 &fifo_write_pages, 1228 1229 NULL, // io() 1230 NULL, // cancel_io() 1231 1232 NULL, // get_file_map 1233 1234 /* common */ 1235 &fifo_ioctl, 1236 &fifo_set_flags, 1237 &fifo_select, 1238 &fifo_deselect, 1239 &fifo_fsync, 1240 1241 NULL, // fs_read_link 1242 NULL, // fs_symlink 1243 NULL, // fs_link 1244 NULL, // unlink 1245 NULL, // rename 1246 1247 NULL, // fs_access() 1248 &fifo_read_stat, 1249 &fifo_write_stat, 1250 NULL, 1251 1252 /* file */ 1253 NULL, // create() 1254 &fifo_open, 1255 &fifo_close, 1256 &fifo_free_cookie, 1257 &fifo_read, 1258 &fifo_write, 1259 1260 /* directory */ 1261 NULL, // create_dir 1262 NULL, // remove_dir 1263 NULL, // open_dir 1264 NULL, // close_dir 1265 NULL, // free_dir_cookie 1266 NULL, // read_dir 1267 NULL, // rewind_dir 1268 1269 /* attribute directory operations */ 1270 NULL, // open_attr_dir 1271 NULL, // close_attr_dir 1272 NULL, // free_attr_dir_cookie 1273 NULL, // read_attr_dir 1274 NULL, // rewind_attr_dir 1275 1276 /* attribute operations */ 1277 NULL, // create_attr 1278 NULL, // open_attr 1279 NULL, // close_attr 1280 NULL, // free_attr_cookie 1281 NULL, // read_attr 1282 NULL, // write_attr 1283 1284 NULL, // read_attr_stat 1285 NULL, // write_attr_stat 1286 NULL, // rename_attr 1287 NULL, // remove_attr 1288 1289 /* support for node and FS layers */ 1290 NULL, // create_special_node 1291 &fifo_get_super_vnode, 1292 }; 1293 1294 1295 } // namespace fifo 1296 1297 1298 using namespace fifo; 1299 1300 1301 // #pragma mark - 1302 1303 1304 status_t 1305 create_fifo_vnode(fs_volume* superVolume, fs_vnode* vnode) 1306 { 1307 FIFOInode* fifo = new(std::nothrow) FIFOInode(vnode); 1308 if (fifo == NULL) 1309 return B_NO_MEMORY; 1310 1311 status_t status = fifo->InitCheck(); 1312 if (status != B_OK) { 1313 delete fifo; 1314 return status; 1315 } 1316 1317 vnode->private_node = fifo; 1318 vnode->ops = &sFIFOVnodeOps; 1319 1320 return B_OK; 1321 } 1322 1323 1324 void 1325 fifo_init() 1326 { 1327 add_debugger_command_etc("fifo", &Inode::Dump, 1328 "Print info about the specified FIFO node", 1329 "[ \"-d\" ] <address>\n" 1330 "Prints information about the FIFO node specified by address\n" 1331 "<address>. If \"-d\" is given, the data in the FIFO's ring buffer\n" 1332 "hexdumped as well.\n", 1333 0); 1334 } 1335