Overview
LibCore is SerenityOS’s core utilities library built on top of AK. It provides essential abstractions for event-driven programming, file I/O, process management, timers, and system integration. LibCore is the foundation for both GUI applications (via LibGUI) and command-line utilities.
LibCore provides cross-platform abstractions with platform-specific implementations for SerenityOS, Linux, and macOS.
Event Loop
EventLoop
Core event loop for asynchronous programming.
#include <LibCore/EventLoop.h>
int main ( int argc , char** argv ) {
Core ::EventLoop event_loop;
// Schedule deferred work
event_loop . deferred_invoke ([]() {
dbgln ( "This runs on next event loop iteration" );
});
// Run the event loop
return event_loop . exec ();
}
Deferred invocations : Run callbacks asynchronously
Timers : Periodic or one-shot timer events
Filesystem notifications : Watch for file changes
POSIX signals : Handle signals in event loop
Coroutine support : Async/await style programming
Nested event loops : Support for modal dialogs
Key Methods:
Pump the event loop until exit is requested. Returns exit code.
Process events once. Returns number of events processed.
Request event loop exit with given exit code.
Schedule callback to run on next event loop iteration.
Pump event loop until condition becomes true.
// Spin until condition met
bool ready = false ;
event_loop . spin_until ([ & ] { return ready; });
// Quit event loop
event_loop . quit ( 0 );
EventReceiver
Base class for objects that receive events.
#include <LibCore/EventReceiver.h>
#include <LibCore/Event.h>
class MyObject : public Core :: EventReceiver {
C_OBJECT ( MyObject )
public:
virtual void timer_event ( Core :: TimerEvent & event ) override {
dbgln ( "Timer fired!" );
}
virtual void custom_event ( Core :: CustomEvent & event ) override {
dbgln ( "Custom event: {}" , event . custom_type ());
}
private:
MyObject () = default ;
};
File I/O
File
Modern file I/O using streams.
#include <LibCore/File.h>
// Open file for reading
auto file = TRY ( Core :: File :: open ( "/path/to/file" sv , Core :: File :: OpenMode ::Read));
// Read entire file
auto contents = TRY ( file -> read_until_eof ());
// Read some bytes
u8 buffer [ 1024 ];
auto bytes = TRY ( file -> read_some (buffer));
// Open for writing
auto out = TRY ( Core :: File :: open ( "/tmp/output" sv ,
Core :: File :: OpenMode ::Write | Core :: File :: OpenMode ::Truncate));
TRY ( out -> write_until_depleted ( "Hello, World!" sv . bytes ()));
Reading Files
Writing Files
Standard Streams
// Read entire file as string
auto file = TRY ( Core :: File :: open ( "/etc/passwd" sv , Core :: File :: OpenMode ::Read));
auto buffer = TRY ( file -> read_until_eof ());
auto content = String :: from_utf8_without_validation (buffer);
Open Modes:
Open for reading and writing
Truncate file to zero length
Fail if file already exists
Directory & DirIterator
Directory operations and iteration.
#include <LibCore/Directory.h>
#include <LibCore/DirIterator.h>
// Create directory
TRY ( Core :: Directory :: create ( "/tmp/mydir" sv , 0 755 ));
// Iterate directory entries
Core :: DirIterator iterator ( "/tmp" sv , Core :: DirIterator :: SkipDots );
while ( iterator . has_next ()) {
auto entry = iterator . next ();
dbgln ( "{}: {}" , entry -> name , entry -> type );
}
// Check if directory exists
if ( Core :: Directory :: exists ( "/etc" sv )) {
// Directory exists
}
MappedFile
Memory-mapped file I/O for efficient access.
#include <LibCore/MappedFile.h>
// Map file into memory
auto mapped = TRY ( Core :: MappedFile :: map ( "/path/to/large/file" sv ));
// Access as bytes
ReadonlyBytes bytes = mapped -> bytes ();
// File is automatically unmapped on destruction
Timers
Timer
Schedule periodic or one-shot timer events.
#include <LibCore/Timer.h>
// Create repeating timer
auto timer = Core :: Timer :: create_repeating ( 1000 , []() {
dbgln ( "Tick every second" );
});
timer -> start ();
// Create one-shot timer
auto delayed = Core :: Timer :: create_single_shot ( 5000 , []() {
dbgln ( "Fired after 5 seconds" );
});
delayed -> start ();
// Manual timer control
auto timer = Core :: Timer :: create ();
timer -> set_interval ( 500 ); // 500ms
timer -> set_single_shot ( false ); // Repeating
timer -> on_timeout = []() { dbgln ( "Timeout!" ); };
timer -> start ();
// Stop timer
timer -> stop ();
Timer interval in milliseconds
If true, timer fires once then stops. If false, repeats indefinitely.
Callback invoked when timer fires
Process Management
Process
Spawn and manage child processes.
#include <LibCore/Process.h>
// Spawn process
auto result = TRY ( Core :: Process :: spawn ( "/bin/ls" sv ,
Array { "ls" sv , "-la" sv }));
dbgln ( "Spawned PID: {}" , result . pid );
// Run and wait for completion
auto output = TRY ( Core :: Process :: run (
Array { "/bin/echo" sv , "Hello" sv }));
dbgln ( "Exit code: {}" , output . exit_code );
dbgln ( "Output: {}" , String :: from_utf8 ( output . standard_output ));
// Spawn with custom environment
HashMap < String, String > env;
env . set ( "MY_VAR" _string , "value" _string );
auto result = TRY ( Core :: Process :: spawn ( "/bin/prog" sv ,
Array { "prog" sv }, env));
Spawn Process
Run and Capture Output
// Spawn without waiting
auto result = TRY ( Core :: Process :: spawn (
"/usr/bin/myapp" sv ,
Array { "myapp" sv , "--option" sv , "value" sv }
));
dbgln ( "Process PID: {}" , result . pid );
// Process continues running
Network I/O
Socket
TCP/UDP socket abstraction.
#include <LibCore/Socket.h>
// Connect to server
auto socket = TRY ( Core :: Socket :: connect ( "example.com" sv , 80 ));
// Send data
TRY ( socket -> write_until_depleted ( "GET / HTTP/1.0 \r\n\r\n " sv . bytes ()));
// Read response
auto response = TRY ( socket -> read_until_eof ());
// Socket automatically closes on destruction
TCPServer & UDPServer
Server socket implementations.
#include <LibCore/TCPServer.h>
auto server = TRY ( Core :: TCPServer :: try_create ());
TRY ( server -> listen ({ 127 , 0 , 0 , 1 }, 8080 ));
server -> on_ready_to_accept = [ & ]() {
auto client = server -> accept ();
if (client) {
dbgln ( "Client connected" );
// Handle client...
}
};
Configuration
ConfigFile
INI-style configuration file handling.
#include <LibCore/ConfigFile.h>
// Open config file
auto config = TRY ( Core :: ConfigFile :: open ( "/etc/myapp.conf" sv ));
// Read values
auto value = config -> read_entry ( "Section" sv , "key" sv , "default" sv );
auto number = config -> read_num_entry ( "Section" sv , "count" sv , 0 );
auto flag = config -> read_bool_entry ( "Section" sv , "enabled" sv , false );
// Write values
config -> write_entry ( "Section" sv , "key" sv , "new_value" sv );
config -> write_num_entry ( "Section" sv , "count" sv , 42 );
config -> write_bool_entry ( "Section" sv , "enabled" sv , true );
// Save changes
TRY ( config -> sync ());
Environment
Environment variable access.
#include <LibCore/Environment.h>
// Get variable
if ( auto path = Core :: Environment :: get ( "PATH" sv )) {
dbgln ( "PATH: {}" , * path);
}
// Set variable
TRY ( Core :: Environment :: set ( "MY_VAR" sv , "value" sv , true )); // true = overwrite
// Unset variable
TRY ( Core :: Environment :: unset ( "MY_VAR" sv ));
System Utilities
DateTime
Date and time handling.
#include <LibCore/DateTime.h>
// Current time
auto now = Core :: DateTime :: now ();
dbgln ( "Current time: {}" , now . to_string ());
// From timestamp
auto dt = Core :: DateTime :: from_timestamp ( 1234567890 );
// Formatting
auto formatted = now . to_string ( "%Y-%m- %d %H:%M: %S " sv );
// Components
int year = now . year ();
int month = now . month ();
int day = now . day ();
int hour = now . hour ();
ArgsParser
Command-line argument parsing.
#include <LibCore/ArgsParser.h>
int main ( int argc , char** argv ) {
Core ::ArgsParser parser;
String filename;
bool verbose = false ;
int count = 1 ;
parser . add_positional_argument (filename, "Input file" , "FILE" );
parser . add_option (verbose, "Verbose output" , "verbose" , 'v' );
parser . add_option (count, "Repetition count" , "count" , 'n' , "NUM" );
parser . parse (argc, argv);
dbgln ( "File: {}" , filename);
dbgln ( "Verbose: {}" , verbose);
dbgln ( "Count: {}" , count);
return 0 ;
}
Positional arguments
Boolean flags (—flag, -f)
Value options (—option=value, -o value)
Automatic —help generation
Required vs optional arguments
Type-safe parsing
ElapsedTimer
High-resolution timing.
#include <LibCore/ElapsedTimer.h>
Core ::ElapsedTimer timer;
timer . start ();
// Do some work...
auto elapsed_ms = timer . elapsed ();
dbgln ( "Operation took {}ms" , elapsed_ms);
System
System information and utilities.
#include <LibCore/System.h>
// Get system info
auto hostname = TRY ( Core :: System :: gethostname ());
auto username = TRY ( Core :: System :: getlogin ());
// Change directory
TRY ( Core :: System :: chdir ( "/tmp" sv ));
// Sleep
Core :: System :: sleep ( 1 ); // 1 second
Core :: System :: usleep ( 1000 ); // 1000 microseconds
Promises & Async
Promise
Asynchronous operation results.
#include <LibCore/Promise.h>
NonnullRefPtr < Core :: Promise < String >> async_read_file ( String path ) {
auto promise = Core :: Promise < String >:: construct ();
// Schedule async work
Core :: EventLoop :: current (). deferred_invoke ([ promise , path = move (path)]() {
auto result = Core :: File :: open (path, Core :: File :: OpenMode ::Read);
if ( result . is_error ()) {
promise -> reject ( result . error ());
} else {
auto content = result . value ()-> read_until_eof ();
if ( content . is_error ()) {
promise -> reject ( content . error ());
} else {
promise -> resolve ( String :: from_utf8_without_validation ( content . value ()));
}
}
});
return promise;
}
File Watching
FileWatcher
Monitor file system changes.
#include <LibCore/FileWatcher.h>
auto watcher = TRY ( Core :: FileWatcher :: create ());
TRY ( watcher -> add_watch ( "/path/to/watch" sv ,
Core :: FileWatcherEvent :: Type ::Modified));
watcher -> on_change = []( auto& event ) {
dbgln ( "File changed: {}" , event . path );
};
Best Practices
Create one EventLoop per thread
Use deferred_invoke for async callbacks
Don’t block the event loop with long operations
Use timers for periodic work
// Always use TRY for operations that return ErrorOr
auto file = TRY ( Core :: File :: open (path, Core :: File :: OpenMode ::Read));
// Or handle errors explicitly
if ( auto result = Core :: File :: open (path, mode); result . is_error ()) {
warnln ( "Failed to open: {}" , result . error ());
return 1 ;
}
Use RAII: Resources automatically cleaned up
Files close on destruction
Timers stop on destruction
Sockets disconnect on destruction
AK - Foundation data structures
LibGUI - GUI toolkit built on LibCore
LibIPC - Inter-process communication