hphp/hsl/src/os/README.md
HH\Lib\OSThe namespace is intended to contain very low-level functions, primarily as a
base layer for implementing higher-level libraries (e.g. HH\Lib\IO), and
direct usage should be avoided where possible.
This document is a work in progress, and consists of guidelines, not rules. Expect us to be conservative in what is added, and we aim to expand and clarify this document over time.
open, write, socket)mkostemps)OS\ and other
key Hack functionality, e.g. HH\Lib\OS\poll_async(), allowing awaiting
on HH\Lib\FileDescriptors.For now, functions for use in HSL IO are high priority; it is expected that the exposed set will grow over time.
malloc)pthread_create.In general, we aim to make minimum changes to fit Hack; man 2 somefunc
(BSD and POSIX) man 3 somefunc (libc) should be usable as the source of
highly detailed documentation.
We recommend referring to Python's os and sockets modules; they are an
inspiration for several decisions in this library.
errno is an unsafe concept in HHVM.0 or 1), the HSL function should return void, with an exception
on failureOS\ErrnoException or subclasses.
_OS\ErrnoException, which is final._OS\throw_errno() to throw an appropriate
subclass of OS\ErrnoException_OS\wrap_impl() to convert
the native exceptions into the public exceptions.OS\ErrnoException if the error condition would not be indicated
by the errno variable in C. Consider adding another similar class, e.g.
add OS\HErrnoException if you want to report an error exposed via h_errnoOS\open() returns a HH\Lib\FileDescriptor instead of
an int; as well as aiding type safety, this prevents requests from
interfering with resources that belong to another request.inout parameters; return tuples instead. For example, prefer
function mkstemp(string $pattern): (FileDescriptor, string) to
function mkstemp(inout string $in_pattern_out_path): FileDescriptor
vec
or shape. See Appendix: reference transparent C pointer
encoding section for more
detail.open()). If a function mentions "the current process"
(e.g. flock()), seek advise - this can be intrincate.X
characters in mkstemp patterns, Linux requires 6. The HSL should report
EINVAL for < 6 on all platforms.EINTR on both Linux and Mac; retrying may be unsafe
(e.g. close())poll_async()
fails with ENOTSUP, higher-level libraries (such as HSL IO) should avoid
calling poll_async() on the same FileDescriptor again.sockaddr are always in host byte order, not network byte order.| C type | Hack type |
|---|---|
structs of primitive types or other structs | shape |
| Referential transparent C pointers with unordered setters | shape |
| Referential transparent C pointers with ordered setters | vec |
| Other C handles or pointers | HH\Lib\OS\FileDescriptor or other wrapper classes |
The underlying C API commonly exposes some data type as handles or pointers,
e.g. int filedes, along with functions to create, manipulate, and destroy
them. By default, handles and pointers should be wrapped in HSL as Hack
classes.
However, as an optimization, pointers to referential transparent C structs can
be encoded as a garbage-collectable mirror in Hack, which creates and destroys
the underlying C data type on demand, and destroys it when explicitly cleaned up
by a dedicated function call, or at some later undetermined time which should
not be directly observable by the same request.
Technically, the terminology "referential transparent" should be interpreted as "referential transparent except for memory allocation" in C, while its corresponding Hack mirror is strictly referential transparent, which means there is no behavior change when the user replaces a variable of the referential transparent mirror with the expression creating the variable, and vice-versa.
Referential transparent type can be used interchangeably with "value-like" type.
shapeSome C data types the setters are orthogonal to each other, and the order to
invoke setters does not matter. In that case, the data type can be encoded as a
shape instead of a vec, using the setter function name as the key in the
shape. For example, given the following C data type and the related utility
functions:
// The reference transparent C pointer
typedef void *posix_spawnattr_t;
// The constructor
int posix_spawnattr_init(posix_spawnattr_t *attr);
// The setters
int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
// The destructor
int posix_spawnattr_destroy(posix_spawnattr_t *attr);
The corresponding Hack definition should be:
newtype pid_t = int;
type PosixSpawnFlags = ...;
type posix_spawnattr_t = shape(
'posix_spawnattr_setpgroup' => pid_t,
'posix_spawnattr_setflags' => PosixSpawnFlags,
);
vecThe general way to encode a pointer to referential transparent C struct is to
consider the data type as a vec of a setter interface implemented by setter
classes, each of which correspond to a setter function. For example, given the
following referential transparent C pointer and the related utility functions:
// The referential transparent C pointer
typedef void *posix_spawn_file_actions_t;
// The constructor
int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions);
// The setters
int posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t *file_actions, const char *restrict path);
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, int filedes, int newfiledes);
// The destructor
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions);
The corresponding Hack definition should be:
<<__Sealed(
posix_spawn_file_actions_addchdir::class,
posix_spawn_file_actions_adddup2::class
)>>
interface PosixSpawnFileActionsSetter {}
final class posix_spawn_file_actions_addchdir implements PosixSpawnFileActionsSetter {
public function __construct(public string $path) {}
}
final class posix_spawn_file_actions_adddup2 implements PosixSpawnFileActionsSetter {
public function __construct(
public FileDescriptor $filedes,
public int $newfiledes,
) {}
}
type posix_spawn_file_actions_t = vec<PosixSpawnFileActionsSetter>;