root/headers/os/kernel/OS.h
/*
 * Copyright 2004-2019, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */
#ifndef _OS_H
#define _OS_H

/** Kernel specific structures and functions */

#include <limits.h>
#include <stdarg.h>
#include <sys/types.h>

#include <SupportDefs.h>
#include <StorageDefs.h>


#ifdef __cplusplus
extern "C" {
#endif

/* System constants */

#define B_OS_NAME_LENGTH        32
#define B_INFINITE_TIMEOUT      (0x7FFFFFFFFFFFFFFFLL)

#define B_PAGE_SIZE                     PAGESIZE

enum {
        B_TIMEOUT                                               = 0x8,  /* relative timeout */
        B_RELATIVE_TIMEOUT                              = 0x8,  /* fails after a relative timeout
                                                                                                with B_TIMED_OUT */
        B_ABSOLUTE_TIMEOUT                              = 0x10, /* fails after an absolute timeout
                                                                                                with B_TIMED_OUT */

        /* experimental Haiku only API */
        B_TIMEOUT_REAL_TIME_BASE                = 0x40,
        B_ABSOLUTE_REAL_TIME_TIMEOUT    = B_ABSOLUTE_TIMEOUT
                                                                                | B_TIMEOUT_REAL_TIME_BASE
                                                                /* fails after an absolute timeout
                                                                                                with B_TIMED_OUT based on the
                                                                                                real time clock */
};


/* Types */

typedef int32 area_id;
typedef int32 port_id;
typedef int32 sem_id;
typedef int32 team_id;
typedef int32 thread_id;


/* Areas */

typedef struct area_info {
        area_id         area;
        char            name[B_OS_NAME_LENGTH];
        size_t          size;
        uint32          lock;
        uint32          protection;
        team_id         team;
        uint32          ram_size;
        uint32          copy_count;
        uint32          in_count;
        uint32          out_count;
        void            *address;
} area_info;

/* area locking */
#define B_NO_LOCK                               0
#define B_LAZY_LOCK                             1
#define B_FULL_LOCK                             2
#define B_CONTIGUOUS                    3
#define B_LOMEM                                 4       /* B_CONTIGUOUS, < 16 MB physical address */
#define B_32_BIT_FULL_LOCK              5       /* B_FULL_LOCK, < 4 GB physical addresses */
#define B_32_BIT_CONTIGUOUS             6       /* B_CONTIGUOUS, < 4 GB physical address */

/* address spec for create_area(), and clone_area() */
#define B_ANY_ADDRESS                           0
#define B_EXACT_ADDRESS                         1
#define B_BASE_ADDRESS                          2
#define B_CLONE_ADDRESS                         3
#define B_ANY_KERNEL_ADDRESS            4
/* B_ANY_KERNEL_BLOCK_ADDRESS           5 */
#define B_RANDOMIZED_ANY_ADDRESS        6
#define B_RANDOMIZED_BASE_ADDRESS       7

/* area protection */
#define B_READ_AREA                             (1 << 0)
#define B_WRITE_AREA                    (1 << 1)
#define B_EXECUTE_AREA                  (1 << 2)
#define B_STACK_AREA                    (1 << 3)
        /* "stack" protection is not available on most platforms - it's used
           to only commit memory as needed, and have guard pages at the
           bottom of the stack. */
#define B_CLONEABLE_AREA                (1 << 8)

extern area_id          create_area(const char *name, void **startAddress,
                                                uint32 addressSpec, size_t size, uint32 lock,
                                                uint32 protection);
extern area_id          clone_area(const char *name, void **destAddress,
                                                uint32 addressSpec, uint32 protection, area_id source);
extern area_id          find_area(const char *name);
extern area_id          area_for(void *address);
extern status_t         delete_area(area_id id);
extern status_t         resize_area(area_id id, size_t newSize);
extern status_t         set_area_protection(area_id id, uint32 newProtection);

/* system private, use macros instead */
extern status_t         _get_area_info(area_id id, area_info *areaInfo, size_t size);
extern status_t         _get_next_area_info(team_id team, ssize_t *cookie,
                                                area_info *areaInfo, size_t size);

#define get_area_info(id, areaInfo) \
        _get_area_info((id), (areaInfo),sizeof(*(areaInfo)))
#define get_next_area_info(team, cookie, areaInfo) \
        _get_next_area_info((team), (cookie), (areaInfo), sizeof(*(areaInfo)))


/* Ports */

typedef struct port_info {
        port_id         port;
        team_id         team;
        char            name[B_OS_NAME_LENGTH];
        int32           capacity;               /* queue depth */
        int32           queue_count;    /* # msgs waiting to be read */
        int32           total_count;    /* total # msgs read so far */
} port_info;

extern port_id          create_port(int32 capacity, const char *name);
extern port_id          find_port(const char *name);
extern ssize_t          read_port(port_id port, int32 *code, void *buffer,
                                                size_t bufferSize);
extern ssize_t          read_port_etc(port_id port, int32 *code, void *buffer,
                                                size_t bufferSize, uint32 flags, bigtime_t timeout);
extern status_t         write_port(port_id port, int32 code, const void *buffer,
                                                size_t bufferSize);
extern status_t         write_port_etc(port_id port, int32 code, const void *buffer,
                                                size_t bufferSize, uint32 flags, bigtime_t timeout);
extern status_t         close_port(port_id port);
extern status_t         delete_port(port_id port);

extern ssize_t          port_buffer_size(port_id port);
extern ssize_t          port_buffer_size_etc(port_id port, uint32 flags,
                                                bigtime_t timeout);
extern ssize_t          port_count(port_id port);
extern status_t         set_port_owner(port_id port, team_id team);

/* system private, use the macros instead */
extern status_t         _get_port_info(port_id port, port_info *portInfo,
                                                size_t portInfoSize);
extern status_t         _get_next_port_info(team_id team, int32 *cookie,
                                                port_info *portInfo, size_t portInfoSize);

#define get_port_info(port, info) \
        _get_port_info((port), (info), sizeof(*(info)))
#define get_next_port_info(team, cookie, info) \
        _get_next_port_info((team), (cookie), (info), sizeof(*(info)))


/* WARNING: The following is Haiku experimental API. It might be removed or
   changed in the future. */

typedef struct port_message_info {
        size_t          size;
        uid_t           sender;
        gid_t           sender_group;
        team_id         sender_team;
} port_message_info;

/* similar to port_buffer_size_etc(), but returns (more) info */
extern status_t         _get_port_message_info_etc(port_id port,
                                                port_message_info *info, size_t infoSize, uint32 flags,
                                                bigtime_t timeout);

#define get_port_message_info_etc(port, info, flags, timeout) \
        _get_port_message_info_etc((port), (info), sizeof(*(info)), flags, timeout)


/* Semaphores */

typedef struct sem_info {
        sem_id          sem;
        team_id         team;
        char            name[B_OS_NAME_LENGTH];
        int32           count;
        thread_id       latest_holder;
} sem_info;

/* semaphore flags */
enum {
        B_CAN_INTERRUPT                         = 0x01, /* acquisition of the semaphore can be
                                                                                   interrupted (system use only) */
        B_CHECK_PERMISSION                      = 0x04, /* ownership will be checked (system use
                                                                                   only) */
        B_KILL_CAN_INTERRUPT            = 0x20, /* acquisition of the semaphore can be
                                                                                   interrupted by SIGKILL[THR], even
                                                                                   if not B_CAN_INTERRUPT (system use
                                                                                   only) */

        /* release_sem_etc() only flags */
        B_DO_NOT_RESCHEDULE                     = 0x02, /* thread is not rescheduled */
        B_RELEASE_ALL                           = 0x08, /* all waiting threads will be woken up,
                                                                                   count will be zeroed */
        B_RELEASE_IF_WAITING_ONLY       = 0x10  /* release count only if there are any
                                                                                   threads waiting */
};

extern sem_id           create_sem(int32 count, const char *name);
extern status_t         delete_sem(sem_id id);
extern status_t         acquire_sem(sem_id id);
extern status_t         acquire_sem_etc(sem_id id, int32 count, uint32 flags,
                                                bigtime_t timeout);
extern status_t         release_sem(sem_id id);
extern status_t         release_sem_etc(sem_id id, int32 count, uint32 flags);
/* TODO: the following two calls are not part of the BeOS API, and might be
   changed or even removed for the final release of Haiku R1 */
extern status_t         switch_sem(sem_id semToBeReleased, sem_id id);
extern status_t         switch_sem_etc(sem_id semToBeReleased, sem_id id,
                                                int32 count, uint32 flags, bigtime_t timeout);
extern status_t         get_sem_count(sem_id id, int32 *threadCount);
extern status_t         set_sem_owner(sem_id id, team_id team);

/* system private, use the macros instead */
extern status_t         _get_sem_info(sem_id id, struct sem_info *info,
                                                size_t infoSize);
extern status_t         _get_next_sem_info(team_id team, int32 *cookie,
                                                struct sem_info *info, size_t infoSize);

#define get_sem_info(sem, info) \
        _get_sem_info((sem), (info), sizeof(*(info)))

#define get_next_sem_info(team, cookie, info) \
        _get_next_sem_info((team), (cookie), (info), sizeof(*(info)))


/* Teams */

typedef struct {
        team_id                 team;
        int32                   thread_count;
        int32                   image_count;
        int32                   area_count;
        thread_id               debugger_nub_thread;
        port_id                 debugger_nub_port;
        int32                   argc;
        char                    args[64];
        uid_t                   uid;
        gid_t                   gid;

        /* Haiku R1 extensions */
        uid_t                   real_uid;
        gid_t                   real_gid;
        pid_t                   group_id;
        pid_t                   session_id;
        team_id                 parent;
        char                    name[B_OS_NAME_LENGTH];
        bigtime_t               start_time;
} team_info;

#define B_CURRENT_TEAM  0
#define B_SYSTEM_TEAM   1

extern status_t         kill_team(team_id team);
        /* see also: send_signal() */

/* system private, use macros instead */
extern status_t         _get_team_info(team_id id, team_info *info, size_t size);
extern status_t         _get_next_team_info(int32 *cookie, team_info *info,
                                                size_t size);

#define get_team_info(id, info) \
        _get_team_info((id), (info), sizeof(*(info)))

#define get_next_team_info(cookie, info) \
        _get_next_team_info((cookie), (info), sizeof(*(info)))

/* team usage info */

typedef struct {
        bigtime_t               user_time;
        bigtime_t               kernel_time;
} team_usage_info;

enum {
        /* compatible to sys/resource.h RUSAGE_SELF and RUSAGE_CHILDREN */
        B_TEAM_USAGE_SELF               = 0,
        B_TEAM_USAGE_CHILDREN   = -1
};

/* system private, use macros instead */
extern status_t         _get_team_usage_info(team_id team, int32 who,
                                                team_usage_info *info, size_t size);

#define get_team_usage_info(team, who, info) \
        _get_team_usage_info((team), (who), (info), sizeof(*(info)))


/* Threads */

typedef enum {
        B_THREAD_RUNNING        = 1,
        B_THREAD_READY,
        B_THREAD_RECEIVING,
        B_THREAD_ASLEEP,
        B_THREAD_SUSPENDED,
        B_THREAD_WAITING
} thread_state;

typedef struct {
        thread_id               thread;
        team_id                 team;
        char                    name[B_OS_NAME_LENGTH];
        thread_state    state;
        int32                   priority;
        sem_id                  sem;
        bigtime_t               user_time;
        bigtime_t               kernel_time;
        void                    *stack_base;
        void                    *stack_end;
} thread_info;

#define B_IDLE_PRIORITY                                 0
#define B_LOWEST_ACTIVE_PRIORITY                1
#define B_LOW_PRIORITY                                  5
#define B_NORMAL_PRIORITY                               10
#define B_DISPLAY_PRIORITY                              15
#define B_URGENT_DISPLAY_PRIORITY               20
#define B_REAL_TIME_DISPLAY_PRIORITY    100
#define B_URGENT_PRIORITY                               110
#define B_REAL_TIME_PRIORITY                    120

#define B_SYSTEM_TIMEBASE                               0
        /* time base for snooze_*(), compatible with the clockid_t constants defined
           in <time.h> */

#define B_FIRST_REAL_TIME_PRIORITY              B_REAL_TIME_DISPLAY_PRIORITY

typedef status_t (*thread_func)(void *);
#define thread_entry thread_func
        /* thread_entry is for backward compatibility only! Use thread_func */

extern thread_id        spawn_thread(thread_func, const char *name, int32 priority,
                                                void *data);
extern status_t         kill_thread(thread_id thread);
extern status_t         resume_thread(thread_id thread);
extern status_t         suspend_thread(thread_id thread);

extern status_t         rename_thread(thread_id thread, const char *newName);
extern status_t         set_thread_priority(thread_id thread, int32 newPriority);
extern void                     exit_thread(status_t status);
extern status_t         wait_for_thread(thread_id thread, status_t *returnValue);
extern status_t         wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
                                                status_t *_returnCode);
extern status_t         on_exit_thread(void (*callback)(void *), void *data);

extern thread_id        find_thread(const char *name);

extern status_t         send_data(thread_id thread, int32 code, const void *buffer,
                                                size_t bufferSize);
extern int32            receive_data(thread_id *sender, void *buffer,
                                                size_t bufferSize);
extern bool                     has_data(thread_id thread);

extern status_t         snooze(bigtime_t amount);
extern status_t         snooze_etc(bigtime_t amount, int timeBase, uint32 flags);
extern status_t         snooze_until(bigtime_t time, int timeBase);

/* system private, use macros instead */
extern status_t         _get_thread_info(thread_id id, thread_info *info, size_t size);
extern status_t         _get_next_thread_info(team_id team, int32 *cookie,
                                                thread_info *info, size_t size);

#define get_thread_info(id, info) \
        _get_thread_info((id), (info), sizeof(*(info)))

#define get_next_thread_info(team, cookie, info) \
        _get_next_thread_info((team), (cookie), (info), sizeof(*(info)))

/* bridge to the pthread API */
extern thread_id        get_pthread_thread_id(pthread_t thread);
/* TODO: Would be nice to have, but we use TLS to associate a thread with its
   pthread object. So this is not trivial to implement.
extern status_t         convert_to_pthread(thread_id thread, pthread_t *_thread);
*/


/* Time */

extern unsigned long real_time_clock(void);
extern void                     set_real_time_clock(unsigned long secsSinceJan1st1970);
extern bigtime_t        real_time_clock_usecs(void);
extern bigtime_t        system_time(void);
                                                /* time since booting in microseconds */
extern nanotime_t       system_time_nsecs(void);
                                                /* time since booting in nanoseconds */

/* Alarm */

enum {
        B_ONE_SHOT_ABSOLUTE_ALARM       = 1,
        B_ONE_SHOT_RELATIVE_ALARM,
        B_PERIODIC_ALARM                        /* "when" specifies the period */
};

extern bigtime_t        set_alarm(bigtime_t when, uint32 flags);


/* Debugger */

extern void                     debugger(const char *message);

/*
   calling this function with a non-zero value will cause your thread
   to receive signals for any exceptional conditions that occur (i.e.
   you'll get SIGSEGV for data access exceptions, SIGFPE for floating
   point errors, SIGILL for illegal instructions, etc).

   to re-enable the default debugger pass a zero.
*/
extern int                      disable_debugger(int state);

/* TODO: Remove. Temporary debug helper. */
extern int                      debug_printf(const char *format, ...)
                                                __attribute__ ((format (__printf__, 1, 2)));
extern int                      debug_vprintf(const char *format, va_list args);
extern void                     ktrace_printf(const char *format, ...)
                                                __attribute__ ((format (__printf__, 1, 2)));
extern void                     ktrace_vprintf(const char *format, va_list args);


/* System information */

typedef struct {
        bigtime_t       active_time;    /* usec of doing useful work since boot */
        bool            enabled;
        uint64          current_frequency;
} cpu_info;

typedef struct {
        bigtime_t               boot_time;                      /* time of boot (usecs since 1/1/1970) */

        uint32                  cpu_count;                      /* number of cpus */

        uint64                  max_pages;                      /* total # of accessible pages */
        uint64                  used_pages;                     /* # of accessible pages in use */
        uint64                  cached_pages;
        uint64                  block_cache_pages;
        uint64                  ignored_pages;          /* # of ignored/inaccessible pages */

        uint64                  needed_memory;
        uint64                  free_memory;

        uint64                  max_swap_pages;
        uint64                  free_swap_pages;

        uint32                  page_faults;            /* # of page faults */

        uint32                  max_sems;
        uint32                  used_sems;

        uint32                  max_ports;
        uint32                  used_ports;

        uint32                  max_threads;
        uint32                  used_threads;

        uint32                  max_teams;
        uint32                  used_teams;

        char                    kernel_name[B_FILE_NAME_LENGTH];
        char                    kernel_build_date[B_OS_NAME_LENGTH];
        char                    kernel_build_time[B_OS_NAME_LENGTH];

        int64                   kernel_version;
        uint32                  abi;                            /* the system API */
} system_info;

enum topology_level_type {
        B_TOPOLOGY_UNKNOWN,
        B_TOPOLOGY_ROOT,
        B_TOPOLOGY_SMT,
        B_TOPOLOGY_CORE,
        B_TOPOLOGY_PACKAGE
};

enum cpu_platform {
        B_CPU_UNKNOWN,
        B_CPU_x86,
        B_CPU_x86_64,
        B_CPU_PPC,
        B_CPU_PPC_64,
        B_CPU_M68K,
        B_CPU_ARM,
        B_CPU_ARM_64,
        B_CPU_ALPHA,
        B_CPU_MIPS,
        B_CPU_SH,
        B_CPU_SPARC,
        B_CPU_RISC_V
};

enum cpu_vendor {
        B_CPU_VENDOR_UNKNOWN,
        B_CPU_VENDOR_AMD,
        B_CPU_VENDOR_CYRIX,
        B_CPU_VENDOR_IDT,
        B_CPU_VENDOR_INTEL,
        B_CPU_VENDOR_NATIONAL_SEMICONDUCTOR,
        B_CPU_VENDOR_RISE,
        B_CPU_VENDOR_TRANSMETA,
        B_CPU_VENDOR_VIA,
        B_CPU_VENDOR_IBM,
        B_CPU_VENDOR_MOTOROLA,
        B_CPU_VENDOR_NEC,
        B_CPU_VENDOR_HYGON,
        B_CPU_VENDOR_SUN,
        B_CPU_VENDOR_FUJITSU
};

typedef struct {
        enum cpu_platform               platform;
} cpu_topology_root_info;

typedef struct {
        enum cpu_vendor                 vendor;
        uint32                                  cache_line_size;
} cpu_topology_package_info;

typedef struct {
        uint32                                  model;
        uint64                                  default_frequency;
} cpu_topology_core_info;

typedef struct {
        uint32                                                  id;
        enum topology_level_type                type;
        uint32                                                  level;

        union {
                cpu_topology_root_info          root;
                cpu_topology_package_info       package;
                cpu_topology_core_info          core;
        } data;
} cpu_topology_node_info;


extern status_t         get_system_info(system_info* info);
extern status_t         _get_cpu_info_etc(uint32 firstCPU, uint32 cpuCount,
                                                cpu_info* info, size_t size);
#define get_cpu_info(firstCPU, cpuCount, info) \
        _get_cpu_info_etc((firstCPU), (cpuCount), (info), sizeof(*(info)))

extern status_t         get_cpu_topology_info(cpu_topology_node_info* topologyInfos,
                                                uint32* topologyInfoCount);

#if defined(__i386__) || defined(__x86_64__)
typedef union {
        struct {
                uint32  max_eax;
                char    vendor_id[12];
        } eax_0;

        struct {
                uint32  stepping                : 4;
                uint32  model                   : 4;
                uint32  family                  : 4;
                uint32  type                    : 2;
                uint32  reserved_0              : 2;
                uint32  extended_model  : 4;
                uint32  extended_family : 8;
                uint32  reserved_1              : 4;

                uint32  brand_index             : 8;
                uint32  clflush                 : 8;
                uint32  logical_cpus    : 8;
                uint32  apic_id                 : 8;

                uint32  features;
                uint32  extended_features;
        } eax_1;

        struct {
                uint8   call_num;
                uint8   cache_descriptors[15];
        } eax_2;

        struct {
                uint32  reserved[2];
                uint32  serial_number_high;
                uint32  serial_number_low;
        } eax_3;

        char            as_chars[16];

        struct {
                uint32  eax;
                uint32  ebx;
                uint32  edx;
                uint32  ecx;
        } regs;
} cpuid_info;

extern status_t         get_cpuid(cpuid_info *info, uint32 eaxRegister,
                                                uint32 cpuNum);
#endif


extern int32            is_computer_on(void);
extern double           is_computer_on_fire(void);


/* signal related functions */
int             send_signal(thread_id threadID, unsigned int signal);
void    set_signal_stack(void* base, size_t size);


/* WARNING: Experimental API! */

enum {
        B_OBJECT_TYPE_FD                = 0,
        B_OBJECT_TYPE_SEMAPHORE = 1,
        B_OBJECT_TYPE_PORT              = 2,
        B_OBJECT_TYPE_THREAD    = 3
};

enum {
        B_EVENT_READ                            = 0x0001,       /* FD/port readable */
        B_EVENT_WRITE                           = 0x0002,       /* FD/port writable */
        B_EVENT_ERROR                           = 0x0004,       /* FD error */
        B_EVENT_PRIORITY_READ           = 0x0008,       /* FD priority readable */
        B_EVENT_PRIORITY_WRITE          = 0x0010,       /* FD priority writable */
        B_EVENT_HIGH_PRIORITY_READ      = 0x0020,       /* FD high priority readable */
        B_EVENT_HIGH_PRIORITY_WRITE     = 0x0040,       /* FD high priority writable */
        B_EVENT_DISCONNECTED            = 0x0080,       /* FD disconnected */

        B_EVENT_ACQUIRE_SEMAPHORE       = 0x0001,       /* semaphore can be acquired */

        B_EVENT_INVALID                         = 0x1000,       /* FD/port/sem/thread ID not or
                                                                                           no longer valid (e.g. has been
                                                                                           close/deleted) */
};

typedef struct object_wait_info {
        int32           object;                                         /* ID of the object */
        uint16          type;                                           /* type of the object */
        uint16          events;                                         /* events mask */
} object_wait_info;

/* wait_for_objects[_etc]() waits until at least one of the specified events or,
   if given, the timeout occurred. When entering the function the
   object_wait_info::events field specifies the events for each object the
   caller is interested in. When the function returns the fields reflect the
   events that actually occurred. The events B_EVENT_INVALID, B_EVENT_ERROR,
   and B_EVENT_DISCONNECTED don't need to be specified. They will always be
   reported, when they occur. */

extern ssize_t          wait_for_objects(object_wait_info* infos, int numInfos);
extern ssize_t          wait_for_objects_etc(object_wait_info* infos, int numInfos,
                                                uint32 flags, bigtime_t timeout);


#ifdef __cplusplus
}
#endif

#endif /* _OS_H */