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 void 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 fWriteCondition; 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 fWriteCondition.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 fWriteCondition.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 fWriteCondition.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_READ); 619 } 620 } else { 621 // Last reader is gone. Wake up all writers. 622 fWriteCondition.NotifyAll(); 623 624 if (fWriteSelectSyncPool) { 625 notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE); 626 notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_ERROR); 627 } 628 } 629 } 630 631 632 void 633 Inode::Open(int openMode) 634 { 635 MutexLocker locker(RequestLock()); 636 637 if ((openMode & O_ACCMODE) == O_WRONLY) 638 fWriterCount++; 639 640 if ((openMode & O_ACCMODE) == O_RDONLY || (openMode & O_ACCMODE) == O_RDWR) 641 fReaderCount++; 642 643 if (fReaderCount > 0 && fWriterCount > 0) { 644 TRACE("Inode %p::Open(): fifo becomes active\n", this); 645 fBuffer.CreateBuffer(); 646 fActive = true; 647 648 // notify all waiting writers that they can start 649 if (fWriteSelectSyncPool) 650 notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE); 651 fWriteCondition.NotifyAll(); 652 } 653 } 654 655 656 void 657 Inode::Close(file_cookie* cookie) 658 { 659 TRACE("Inode %p::Close(openMode = %d)\n", this, openMode); 660 661 MutexLocker locker(RequestLock()); 662 663 int openMode = cookie->open_mode; 664 665 // Notify all currently reading file descriptors 666 ReadRequestList::Iterator iterator = fReadRequests.GetIterator(); 667 while (ReadRequest* request = iterator.Next()) { 668 if (request->Cookie() == cookie) 669 request->Notify(B_FILE_ERROR); 670 } 671 672 if ((openMode & O_ACCMODE) == O_WRONLY && --fWriterCount == 0) 673 NotifyEndClosed(true); 674 675 if ((openMode & O_ACCMODE) == O_RDONLY 676 || (openMode & O_ACCMODE) == O_RDWR) { 677 if (--fReaderCount == 0) 678 NotifyEndClosed(false); 679 } 680 681 if (fWriterCount == 0) { 682 // Notify any still reading writers to stop 683 // TODO: This only works reliable if there is only one writer - we could 684 // do the same thing done for the read requests. 685 fWriteCondition.NotifyAll(B_FILE_ERROR); 686 } 687 688 if (fReaderCount == 0 && fWriterCount == 0) { 689 fActive = false; 690 fBuffer.DeleteBuffer(); 691 } 692 } 693 694 695 status_t 696 Inode::Select(uint8 event, selectsync* sync, int openMode) 697 { 698 bool writer = true; 699 select_sync_pool** pool; 700 if ((openMode & O_RWMASK) == O_RDONLY) { 701 pool = &fReadSelectSyncPool; 702 writer = false; 703 } else if ((openMode & O_RWMASK) == O_WRONLY) { 704 pool = &fWriteSelectSyncPool; 705 } else 706 return B_NOT_ALLOWED; 707 708 if (add_select_sync_pool_entry(pool, sync, event) != B_OK) 709 return B_ERROR; 710 711 // signal right away, if the condition holds already 712 if (writer) { 713 if ((event == B_SELECT_WRITE 714 && (fBuffer.Writable() > 0 || fReaderCount == 0)) 715 || (event == B_SELECT_ERROR && fReaderCount == 0)) { 716 return notify_select_event(sync, event); 717 } 718 } else { 719 if (event == B_SELECT_READ 720 && (fBuffer.Readable() > 0 || fWriterCount == 0)) { 721 return notify_select_event(sync, event); 722 } 723 } 724 725 return B_OK; 726 } 727 728 729 status_t 730 Inode::Deselect(uint8 event, selectsync* sync, int openMode) 731 { 732 select_sync_pool** pool; 733 if ((openMode & O_RWMASK) == O_RDONLY) { 734 pool = &fReadSelectSyncPool; 735 } else if ((openMode & O_RWMASK) == O_WRONLY) { 736 pool = &fWriteSelectSyncPool; 737 } else 738 return B_NOT_ALLOWED; 739 740 remove_select_sync_pool_entry(pool, sync, event); 741 return B_OK; 742 } 743 744 745 void 746 Inode::Dump(bool dumpData) const 747 { 748 kprintf("FIFO %p\n", this); 749 kprintf(" active: %s\n", fActive ? "true" : "false"); 750 kprintf(" readers: %" B_PRId32 "\n", fReaderCount); 751 kprintf(" writers: %" B_PRId32 "\n", fWriterCount); 752 753 if (!fReadRequests.IsEmpty()) { 754 kprintf(" pending readers:\n"); 755 for (ReadRequestList::ConstIterator it = fReadRequests.GetIterator(); 756 ReadRequest* request = it.Next();) { 757 kprintf(" %p: thread %" B_PRId32 ", cookie: %p\n", request, 758 request->GetThread()->id, request->Cookie()); 759 } 760 } 761 762 if (!fWriteRequests.IsEmpty()) { 763 kprintf(" pending writers:\n"); 764 for (WriteRequestList::ConstIterator it = fWriteRequests.GetIterator(); 765 WriteRequest* request = it.Next();) { 766 kprintf(" %p: thread %" B_PRId32 ", min count: %zu\n", request, 767 request->GetThread()->id, request->MinimalWriteCount()); 768 } 769 } 770 771 kprintf(" %zu bytes buffered\n", fBuffer.Readable()); 772 773 if (dumpData && fBuffer.Readable() > 0) { 774 struct DataProvider : BKernel::HexDumpDataProvider { 775 DataProvider(const RingBuffer& buffer) 776 : 777 fBuffer(buffer), 778 fOffset(0) 779 { 780 } 781 782 virtual bool HasMoreData() const 783 { 784 return fOffset < fBuffer.Readable(); 785 } 786 787 virtual uint8 NextByte() 788 { 789 uint8 byte = '\0'; 790 if (fOffset < fBuffer.Readable()) { 791 fBuffer.Peek(fOffset, &byte, 1); 792 fOffset++; 793 } 794 return byte; 795 } 796 797 virtual bool GetAddressString(char* buffer, size_t bufferSize) const 798 { 799 snprintf(buffer, bufferSize, " %4zx", fOffset); 800 return true; 801 } 802 803 private: 804 const RingBuffer& fBuffer; 805 size_t fOffset; 806 }; 807 808 DataProvider dataProvider(fBuffer); 809 BKernel::print_hex_dump(dataProvider, fBuffer.Readable()); 810 } 811 } 812 813 814 /*static*/ int 815 Inode::Dump(int argc, char** argv) 816 { 817 bool dumpData = false; 818 int argi = 1; 819 if (argi < argc && strcmp(argv[argi], "-d") == 0) { 820 dumpData = true; 821 argi++; 822 } 823 824 if (argi >= argc || argi + 2 < argc) { 825 print_debugger_command_usage(argv[0]); 826 return 0; 827 } 828 829 Inode* node = (Inode*)parse_expression(argv[argi]); 830 if (IS_USER_ADDRESS(node)) { 831 kprintf("invalid FIFO address\n"); 832 return 0; 833 } 834 835 node->Dump(dumpData); 836 return 0; 837 } 838 839 840 // #pragma mark - vnode API 841 842 843 static status_t 844 fifo_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 845 { 846 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 847 fs_vnode* superVnode = fifo->SuperVnode(); 848 849 status_t error = B_OK; 850 if (superVnode->ops->put_vnode != NULL) 851 error = superVnode->ops->put_vnode(volume, superVnode, reenter); 852 853 delete fifo; 854 855 return error; 856 } 857 858 859 static status_t 860 fifo_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 861 { 862 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 863 fs_vnode* superVnode = fifo->SuperVnode(); 864 865 status_t error = B_OK; 866 if (superVnode->ops->remove_vnode != NULL) 867 error = superVnode->ops->remove_vnode(volume, superVnode, reenter); 868 869 delete fifo; 870 871 return error; 872 } 873 874 875 static status_t 876 fifo_open(fs_volume* _volume, fs_vnode* _node, int openMode, 877 void** _cookie) 878 { 879 Inode* inode = (Inode*)_node->private_node; 880 881 TRACE("fifo_open(): node = %p, openMode = %d\n", inode, openMode); 882 883 file_cookie* cookie = (file_cookie*)malloc(sizeof(file_cookie)); 884 if (cookie == NULL) 885 return B_NO_MEMORY; 886 887 TRACE(" open cookie = %p\n", cookie); 888 cookie->open_mode = openMode; 889 inode->Open(openMode); 890 891 *_cookie = (void*)cookie; 892 893 return B_OK; 894 } 895 896 897 static status_t 898 fifo_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) 899 { 900 file_cookie* cookie = (file_cookie*)_cookie; 901 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 902 903 fifo->Close(cookie); 904 905 return B_OK; 906 } 907 908 909 static status_t 910 fifo_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) 911 { 912 file_cookie* cookie = (file_cookie*)_cookie; 913 914 TRACE("fifo_freecookie: entry vnode %p, cookie %p\n", _node, _cookie); 915 916 free(cookie); 917 918 return B_OK; 919 } 920 921 922 static status_t 923 fifo_fsync(fs_volume* _volume, fs_vnode* _node) 924 { 925 return B_OK; 926 } 927 928 929 static status_t 930 fifo_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, 931 off_t /*pos*/, void* buffer, size_t* _length) 932 { 933 file_cookie* cookie = (file_cookie*)_cookie; 934 Inode* inode = (Inode*)_node->private_node; 935 936 TRACE("fifo_read(vnode = %p, cookie = %p, length = %lu, mode = %d)\n", 937 inode, cookie, *_length, cookie->open_mode); 938 939 MutexLocker locker(inode->RequestLock()); 940 941 if ((cookie->open_mode & O_RWMASK) != O_RDONLY) 942 return B_NOT_ALLOWED; 943 944 if (inode->IsActive() && inode->WriterCount() == 0) { 945 // as long there is no writer, and the pipe is empty, 946 // we always just return 0 to indicate end of file 947 if (inode->BytesAvailable() == 0) { 948 *_length = 0; 949 return B_OK; 950 } 951 } 952 953 // issue read request 954 955 ReadRequest request(cookie); 956 inode->AddReadRequest(request); 957 958 TRACE(" issue read request %p\n", &request); 959 960 size_t length = *_length; 961 status_t status = inode->ReadDataFromBuffer(buffer, &length, 962 (cookie->open_mode & O_NONBLOCK) != 0, is_called_via_syscall(), 963 request); 964 965 inode->RemoveReadRequest(request); 966 inode->NotifyReadDone(); 967 968 TRACE(" done reading request %p, length %zu\n", &request, length); 969 970 if (length > 0) 971 status = B_OK; 972 973 *_length = length; 974 return status; 975 } 976 977 978 static status_t 979 fifo_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, 980 off_t /*pos*/, const void* buffer, size_t* _length) 981 { 982 file_cookie* cookie = (file_cookie*)_cookie; 983 Inode* inode = (Inode*)_node->private_node; 984 985 TRACE("fifo_write(vnode = %p, cookie = %p, length = %lu)\n", 986 _node, cookie, *_length); 987 988 MutexLocker locker(inode->RequestLock()); 989 990 if ((cookie->open_mode & O_RWMASK) != O_WRONLY) 991 return B_NOT_ALLOWED; 992 993 size_t length = *_length; 994 if (length == 0) 995 return B_OK; 996 997 // copy data into ring buffer 998 status_t status = inode->WriteDataToBuffer(buffer, &length, 999 (cookie->open_mode & O_NONBLOCK) != 0, is_called_via_syscall()); 1000 1001 if (length > 0) 1002 status = B_OK; 1003 1004 *_length = length; 1005 return status; 1006 } 1007 1008 1009 static status_t 1010 fifo_read_stat(fs_volume* volume, fs_vnode* vnode, struct ::stat* st) 1011 { 1012 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 1013 fs_vnode* superVnode = fifo->SuperVnode(); 1014 1015 if (superVnode->ops->read_stat == NULL) 1016 return B_BAD_VALUE; 1017 1018 status_t error = superVnode->ops->read_stat(volume, superVnode, st); 1019 if (error != B_OK) 1020 return error; 1021 1022 1023 MutexLocker locker(fifo->RequestLock()); 1024 1025 st->st_size = fifo->BytesAvailable(); 1026 1027 st->st_blksize = 4096; 1028 1029 // TODO: Just pass the changes to our modification time on to the super node. 1030 st->st_atim.tv_sec = time(NULL); 1031 st->st_atim.tv_nsec = 0; 1032 st->st_mtim = st->st_ctim = fifo->ModificationTime(); 1033 1034 return B_OK; 1035 } 1036 1037 1038 static status_t 1039 fifo_write_stat(fs_volume* volume, fs_vnode* vnode, const struct ::stat* st, 1040 uint32 statMask) 1041 { 1042 // we cannot change the size of anything 1043 if ((statMask & B_STAT_SIZE) != 0) 1044 return B_BAD_VALUE; 1045 1046 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 1047 fs_vnode* superVnode = fifo->SuperVnode(); 1048 1049 if (superVnode->ops->write_stat == NULL) 1050 return B_BAD_VALUE; 1051 1052 status_t error = superVnode->ops->write_stat(volume, superVnode, st, 1053 statMask); 1054 if (error != B_OK) 1055 return error; 1056 1057 return B_OK; 1058 } 1059 1060 1061 static status_t 1062 fifo_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 op, 1063 void* buffer, size_t length) 1064 { 1065 file_cookie* cookie = (file_cookie*)_cookie; 1066 Inode* inode = (Inode*)_node->private_node; 1067 1068 TRACE("fifo_ioctl: vnode %p, cookie %p, op %ld, buf %p, len %ld\n", 1069 _vnode, _cookie, op, buffer, length); 1070 1071 switch (op) { 1072 case FIONBIO: 1073 { 1074 if (buffer == NULL) 1075 return B_BAD_VALUE; 1076 1077 int value; 1078 if (is_called_via_syscall()) { 1079 if (!IS_USER_ADDRESS(buffer) 1080 || user_memcpy(&value, buffer, sizeof(int)) != B_OK) { 1081 return B_BAD_ADDRESS; 1082 } 1083 } else 1084 value = *(int*)buffer; 1085 1086 MutexLocker locker(inode->RequestLock()); 1087 cookie->SetNonBlocking(value != 0); 1088 return B_OK; 1089 } 1090 1091 case FIONREAD: 1092 { 1093 if (buffer == NULL) 1094 return B_BAD_VALUE; 1095 1096 MutexLocker locker(inode->RequestLock()); 1097 int available = (int)inode->BytesAvailable(); 1098 locker.Unlock(); 1099 1100 if (is_called_via_syscall()) { 1101 if (!IS_USER_ADDRESS(buffer) 1102 || user_memcpy(buffer, &available, sizeof(available)) 1103 != B_OK) { 1104 return B_BAD_ADDRESS; 1105 } 1106 } else 1107 *(int*)buffer = available; 1108 1109 return B_OK; 1110 } 1111 1112 case B_SET_BLOCKING_IO: 1113 case B_SET_NONBLOCKING_IO: 1114 { 1115 MutexLocker locker(inode->RequestLock()); 1116 cookie->SetNonBlocking(op == B_SET_NONBLOCKING_IO); 1117 return B_OK; 1118 } 1119 } 1120 1121 return EINVAL; 1122 } 1123 1124 1125 static status_t 1126 fifo_set_flags(fs_volume* _volume, fs_vnode* _node, void* _cookie, 1127 int flags) 1128 { 1129 Inode* inode = (Inode*)_node->private_node; 1130 file_cookie* cookie = (file_cookie*)_cookie; 1131 1132 TRACE("fifo_set_flags(vnode = %p, flags = %x)\n", _vnode, flags); 1133 1134 MutexLocker locker(inode->RequestLock()); 1135 cookie->open_mode = (cookie->open_mode & ~(O_APPEND | O_NONBLOCK)) | flags; 1136 return B_OK; 1137 } 1138 1139 1140 static status_t 1141 fifo_select(fs_volume* _volume, fs_vnode* _node, void* _cookie, 1142 uint8 event, selectsync* sync) 1143 { 1144 file_cookie* cookie = (file_cookie*)_cookie; 1145 1146 TRACE("fifo_select(vnode = %p)\n", _node); 1147 Inode* inode = (Inode*)_node->private_node; 1148 if (!inode) 1149 return B_ERROR; 1150 1151 MutexLocker locker(inode->RequestLock()); 1152 return inode->Select(event, sync, cookie->open_mode); 1153 } 1154 1155 1156 static status_t 1157 fifo_deselect(fs_volume* _volume, fs_vnode* _node, void* _cookie, 1158 uint8 event, selectsync* sync) 1159 { 1160 file_cookie* cookie = (file_cookie*)_cookie; 1161 1162 TRACE("fifo_deselect(vnode = %p)\n", _node); 1163 Inode* inode = (Inode*)_node->private_node; 1164 if (inode == NULL) 1165 return B_ERROR; 1166 1167 MutexLocker locker(inode->RequestLock()); 1168 return inode->Deselect(event, sync, cookie->open_mode); 1169 } 1170 1171 1172 static bool 1173 fifo_can_page(fs_volume* _volume, fs_vnode* _node, void* cookie) 1174 { 1175 return false; 1176 } 1177 1178 1179 static status_t 1180 fifo_read_pages(fs_volume* _volume, fs_vnode* _node, void* cookie, off_t pos, 1181 const iovec* vecs, size_t count, size_t* _numBytes) 1182 { 1183 return B_NOT_ALLOWED; 1184 } 1185 1186 1187 static status_t 1188 fifo_write_pages(fs_volume* _volume, fs_vnode* _node, void* cookie, 1189 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 1190 { 1191 return B_NOT_ALLOWED; 1192 } 1193 1194 1195 static status_t 1196 fifo_get_super_vnode(fs_volume* volume, fs_vnode* vnode, fs_volume* superVolume, 1197 fs_vnode* _superVnode) 1198 { 1199 FIFOInode* fifo = (FIFOInode*)vnode->private_node; 1200 fs_vnode* superVnode = fifo->SuperVnode(); 1201 1202 if (superVnode->ops->get_super_vnode != NULL) { 1203 return superVnode->ops->get_super_vnode(volume, superVnode, superVolume, 1204 _superVnode); 1205 } 1206 1207 *_superVnode = *superVnode; 1208 1209 return B_OK; 1210 } 1211 1212 1213 static fs_vnode_ops sFIFOVnodeOps = { 1214 NULL, // lookup 1215 NULL, // get_vnode_name 1216 // TODO: This is suboptimal! We'd need to forward the 1217 // super node's hook, if it has got one. 1218 1219 &fifo_put_vnode, 1220 &fifo_remove_vnode, 1221 1222 &fifo_can_page, 1223 &fifo_read_pages, 1224 &fifo_write_pages, 1225 1226 NULL, // io() 1227 NULL, // cancel_io() 1228 1229 NULL, // get_file_map 1230 1231 /* common */ 1232 &fifo_ioctl, 1233 &fifo_set_flags, 1234 &fifo_select, 1235 &fifo_deselect, 1236 &fifo_fsync, 1237 1238 NULL, // fs_read_link 1239 NULL, // fs_symlink 1240 NULL, // fs_link 1241 NULL, // unlink 1242 NULL, // rename 1243 1244 NULL, // fs_access() 1245 &fifo_read_stat, 1246 &fifo_write_stat, 1247 NULL, 1248 1249 /* file */ 1250 NULL, // create() 1251 &fifo_open, 1252 &fifo_close, 1253 &fifo_free_cookie, 1254 &fifo_read, 1255 &fifo_write, 1256 1257 /* directory */ 1258 NULL, // create_dir 1259 NULL, // remove_dir 1260 NULL, // open_dir 1261 NULL, // close_dir 1262 NULL, // free_dir_cookie 1263 NULL, // read_dir 1264 NULL, // rewind_dir 1265 1266 /* attribute directory operations */ 1267 NULL, // open_attr_dir 1268 NULL, // close_attr_dir 1269 NULL, // free_attr_dir_cookie 1270 NULL, // read_attr_dir 1271 NULL, // rewind_attr_dir 1272 1273 /* attribute operations */ 1274 NULL, // create_attr 1275 NULL, // open_attr 1276 NULL, // close_attr 1277 NULL, // free_attr_cookie 1278 NULL, // read_attr 1279 NULL, // write_attr 1280 1281 NULL, // read_attr_stat 1282 NULL, // write_attr_stat 1283 NULL, // rename_attr 1284 NULL, // remove_attr 1285 1286 /* support for node and FS layers */ 1287 NULL, // create_special_node 1288 &fifo_get_super_vnode, 1289 }; 1290 1291 1292 } // namespace fifo 1293 1294 1295 using namespace fifo; 1296 1297 1298 // #pragma mark - 1299 1300 1301 status_t 1302 create_fifo_vnode(fs_volume* superVolume, fs_vnode* vnode) 1303 { 1304 FIFOInode* fifo = new(std::nothrow) FIFOInode(vnode); 1305 if (fifo == NULL) 1306 return B_NO_MEMORY; 1307 1308 status_t status = fifo->InitCheck(); 1309 if (status != B_OK) { 1310 delete fifo; 1311 return status; 1312 } 1313 1314 vnode->private_node = fifo; 1315 vnode->ops = &sFIFOVnodeOps; 1316 1317 return B_OK; 1318 } 1319 1320 1321 void 1322 fifo_init() 1323 { 1324 add_debugger_command_etc("fifo", &Inode::Dump, 1325 "Print info about the specified FIFO node", 1326 "[ \"-d\" ] <address>\n" 1327 "Prints information about the FIFO node specified by address\n" 1328 "<address>. If \"-d\" is given, the data in the FIFO's ring buffer\n" 1329 "hexdumped as well.\n", 1330 0); 1331 } 1332