FBB::Pipe(3bobcat)

🌸 FBB::Pipe πŸ’…

okay bestie, welcome to the System Level Communication Pipe glow-up ✨ this one lives in the bobcat manual, section 3, and it is genuinely iconic for talking between processes. no cap.


✨ NAME ✨

FBB::Pipe β€” defines a system level communication pipe 🫢


πŸŽ€ SYNOPSIS πŸŽ€

#include <bobcat/pipe>
Linking option: -lbobcat

πŸ¦‹ DESCRIPTION πŸ¦‹

so like, an FBB::Pipe object is basically how you build a pipe. it gives u the cutest lil interface to the reading end and the writing end, and ngl it's just an object-wrapper hanging out around the pipe(2) system call. main character energy fr fr.

when a Pipe object gets created right before a program forks, it can set up a whole line of communication between the parent and the child process. the way that works is: whatever the child writes to its standard output stream can be redirected into the writing end of the pipe β€” that's the writtenBy member doing the work πŸ’–. then the stuff showing up at the reading end of the pipe can be pulled out using, like, an IFdStream object initialized with the Pipe's reading file descriptor. OR you can redirect the reading end to an existing stream whose file descriptor you already know, like cin (which uses the STDIN_FILENO file descriptor). obsessed.

okay this next bit is IMPORTANT so listen closely: when a Pipe object goes out of scope, no close(2) operation is performed on the pipe's file descriptors. like, none. zero. so after you've set up the pipe with the Pipe's member functions and passed those file descriptors to the code that's gonna use them, the Pipe object might even get destroyed and it's totally fine β€” the using code is the one responsible for closing the pipe. if you do want the pipe closed at destruction time, you can derive a class from Pipe(3bobcat) and write a destructor that closes it. alternatively, Pope's close member can just be called. either way slay. πŸ’…

the value -1 means that a file descriptor isn't referring to a pipe(2) file descriptor. noted bestie πŸ“

and when a pipe has to be reused while forking multiple times? use its reset member before forking. do not forget. i will know. 🌈


πŸ’œ NAMESPACE πŸ’œ

FBB

everything mentioned in this man-page β€” all constructors, members, operators and manipulators β€” lives in the namespace FBB. cute right? everything's in one place πŸŽ€


🌸 INHERITS FROM 🌸

-

(nothing! it inherits from nothing, it's a self-made icon 😌)


⭐ CONSTRUCTORS ⭐

  • Pipe() β€” the default Pipe constructor constructs a pipe, calling pipe(2).
⚠️ this constructor throws an Exception exception if the default Pipe constructor did not properly complete. the thrown Exception object's which() member shows the system's errno value set by the failing pipe(2) function. so if it's mad, ask it which() 🫢
  • Pipe(Pipe &&tmp) β€” the move constructor moves the temporary object's file descriptors into the Pipe object being constructed. get that relocation πŸ’«
  • Pipe(int const *fd) β€” this constructor expects two file descriptors, referring to the read and write file descriptors as returned by pipe(2). it's giving "i already have the fds, thanks".
  • Pipe(bool initialize) β€” this constructor is for when the Pipe object should not be associated with an existing pipe. instead, when initialize == false, it initializes its read and write file descriptors to -1. this one's for classes that define Pipe data members which can only open their pipes after the object has been constructed. once you've built a Pipe obj{ false } object, it can be associated with an open pipe using obj = Pipe{}. or obj.reset(). and if you pass the argument true? then it initializes its pipe (cf. pipe(2)). boom πŸ’₯

copy construction and copy assignment are not defined. do not use move assignment to prepare the pipe when repeatedly forking β€” in those cases use the reset member. periodt.

also note that Pipe's destructor does not close the pipe's file descriptors. to close the pipes, close must be called. say it with me: close must be called πŸ—£οΈ


πŸ”₯ OVERLOADED OPERATOR πŸ”₯

  • Pipe &operator=(Pipe &&tmp) β€” this overloaded move assignment operator closes the current pipe and moves tmp's pipes to the current Pipe object.
😭 again bestie: do not use the move assignment to prepare the pipe when repeatedly forking. in those cases use the reset member. i'm not repeating myself a third time... okay maybe i am, it's important.

πŸ‘‘ MEMBER FUNCTIONS πŸ‘‘

  • void close() β€” both file descriptors of the Pipe object are closed.
  • void closeReadFd() β€” the file descriptor of the Pipe object that's associated with the reading end of the pipe is closed.
  • void closeWriteFd() β€” the file descriptor of the Pipe object that's associated with the writing end of the pipe is closed.
  • int readFd() const β€” returns the pipe's file descriptor that is used for reading πŸ“–
  • void readFrom(int filedescriptor) β€” sets up redirection from the internal read filedescriptor to the given filedescriptor: information written to the write-end of the pipe may be retrieved by extracting the information from the stream that is associated with the indicated file descriptor. e.g., after the call readFrom(STDIN_FILENO) information inserted into the write-end of the pipe can be retrieved from cin. the original read file descriptor and the pipe's write file descriptor are closed. πŸ”„
  • void readFrom(int const *filedescriptors, size_t n) β€” sets up redirection from the internal read filedescriptor to the given filedescriptors: information is read from the Pipe object when reading from any of the n provided filedescriptors. the original read file descriptor and the pipe's write file descriptor are closed.
  • int readOnly() β€” closes the writing end of the pipe, returns the reading end's file descriptor. this member can be used, e.g., to construct an IFdStream object to extract the information that's inserted into the write-end of the pipe. chef's kiss 🀌
  • int readOnlyFd() β€” same as the previous member, but sets the internally used read file descriptor to -1. (this member can be used to, e.g., pass the read file descriptor to another object which eventually closes the pipe's reading end.) handing off the baton πŸƒβ™€οΈ
  • void reset() β€” closes the the current pipe and reopens it with new pipe read and write destriptors. use this member to prepare the pipe when repeatedly forking. ✨
  • void reset(int const *fds) β€” closes the the current pipe and reopens it with the read and write file destriptors provided by the first two elements of fds.
  • void swap(Pipe &other) β€” the current and other Pipe objects are swapped. following this call the current Pipe objects refer to the other object's pipe file descriptors and vice versa. trading places πŸ‘―
  • int writeFd() const β€” returns the pipe's file descriptor that is used for writing. ✍️
  • void writtenBy(int filedescriptor) β€” sets up redirection from the internal write filedescriptor to the given filedescriptor: information is written to the Pipe object when writing to the provided filedescriptor. e.g., after the call writtenBy(STDOUT_FILENO) information sent to the standard output stream (by either cout or by a child process (cf. exec(3))) is inserted into the write-end of the pipe. the original write file descriptor and the pipe's read file descriptor are closed. 🚰
  • void writtenBy(int const *filedescriptors, size_t n) β€” sets up redirection from the internal write filedescriptor to the given filedescriptors: information is inserted into the write-end of the Pipe object when writing to each of the n provided filedescriptors. e.g., when passing an array of two int values, respectively equal to STDOUT_FILENO and STDERR_FILENO to this member, all information which is thereafter sent to the standard output or error streams is inserted into the write-end of the pipe. the original write file descriptor and the pipe's read file descriptor are closed. catch all the output, no crumbs πŸ’…
  • int writeOnly() β€” closes the reading end of the pipe, returns the writing end's file descriptor.
  • int writeOnlyFd() β€” same as the previous member, but sets the internally used write file descriptor to -1. (this member can be used to, e.g., pass the write file descriptor to another object which eventually closes the pipe's writing end.)

🌈 PROTECTED ENUMERATION 🌈

the RW protected enumeration has the following elements, bestie:

  • READ β€” the index in d_fd[] (see below) of the element holding the pipe's reading file descriptor;
  • WRITE β€” the index in d_fd[] (see below) of the element holding the pipe's writing file descriptor.

πŸ’– PROTECTED MEMBER FUNCTION πŸ’–

  • void close(RW rw) β€” when passing argument RW::READ to this member, the reading end of the Pipe object's pipe is closed. when passing argument RW::WRITE, the writing end of the Pipe object's pipe is closed. pick ur fighter πŸ₯Š
  • int *fd() β€” returns a pointer to the two file descriptors (respectively READ and WRITE) currently used by the Pipe object.

πŸ¦„ EXAMPLE πŸ¦„

okay here's the moment you've been waiting for. look at this code, it's gorgeous:

#include <bobcat/pipe>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <iostream>
#include <string>

using namespace std;
using namespace FBB;

int main()
{
    Pipe pipe;                         // construct a pipe

    cout << "Read file descriptor: " << pipe.readFd() << "\n"
            "Write file descriptor: " << pipe.writeFd() << endl;

    int pid = fork();

    if (pid == -1)
        return 1;

    if (pid == 0)                       //child
    {
        pipe.readFrom(STDIN_FILENO);    // read what goes into the pipe

        string s;

        getline(cin, s);
        cout << "CHILD: Got `" << s << "’\n";

        getline(cin, s);
        cout << "CHILD: Got `" << s << "’\n";

        return 0;
    }

    pipe.writtenBy(STDOUT_FILENO);      // write to the pipe via cout

    cout << "first line" << "\n"
            "second line" << ’\n’;

    waitpid(pid, 0, 0);
}

also, go look at the 2nd example over at fork(3bobcat). it's a whole mood πŸ’«


πŸ“ FILES πŸ“

  • bobcat/pipe β€” defines the class interface

πŸ‘€ SEE ALSO πŸ‘€

bobcat(7), fork(3bobcat), pipe(2), mkfifo(3)

go read them, they're all bangers πŸ“š


πŸ’€ BUGS πŸ’€

note that when a Pipe object goes out of scope, no close(2) operation is performed on the pipe's ends. like, at all. if the pipe should be closed by the destructor, derive a class from Pipe(3bobcat), whose destructor performs the required closing-operation. that's the move. don't get caught lacking πŸ™ˆ


🧚 BOBCAT PROJECT FILES 🧚

Debian Bobcat project files:

  • libbobcat6 β€” debian package containing the shared library, changelog and copyright note;
  • libbobcat-dev β€” debian package containing the static library, headers, manual pages, and developer info;

🌈 BOBCAT

okay so BOBCAT is literally an acronym, bestie, and it stands for Brokken’s Own Base Classes And Templates. that's the whole vibe. it's giving "my name is also my whole brand" and honestly? iconic. πŸ’…


this is free software, no cap β€” it's distributed under the terms of the GNU General Public License (GPL). so like, free as in freedom, not free as in "do whatever, we don't care". read the license, bestie, it's important. 🫢


πŸ‘‘ AUTHOR

Frank B. Brokken wrote this. drop him a line at f.b.brokken@rug.nl if you're feeling grateful (he is the "Brokken" in BOBCAT, iykyk). ✨


and that's a wrap on this page, fr fr 🌸 this was part 2 of the FBB::Pipe(3bobcat) manual, from the libbobcat-dev_6.15.01 era β€” the boring version says 2005-2026 for the date, which is a whole couple of decades of Bobcat being out here serving, and honestly? obsessed. go pipe something, main character. πŸ’–πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from