[rpcsx-os/orbis-kernel] random bugfixes

ipmi: fixed respond sync, get message, try get message, try send message
event: detach event emitter from file
signals: basic implementation
linker: fixed zero symbol relocation, fixed exec relocation
shared_cv/mutex: implement eintr response support
shared_cv: fixed possible loop instead of wait
ipmi: implement invoke async, respond async, get result, get client app id, client get name
rpcsx-os: add safemode flag
This commit is contained in:
DH 2024-01-13 20:57:02 +03:00
parent 8791312d4f
commit 65e653f5ef
81 changed files with 2586 additions and 761 deletions

View file

@ -1,16 +1,15 @@
#pragma once
#include "AudioOut.hpp"
#include "KernelAllocator.hpp"
#include "evf.hpp"
#include "ipmi.hpp"
#include "orbis/utils/IdMap.hpp"
#include "osem.hpp"
#include "thread/types.hpp"
#include "utils/IdMap.hpp"
#include "utils/LinkedNode.hpp"
#include "utils/SharedCV.hpp"
#include "utils/SharedMutex.hpp"
#include "AudioOut.hpp"
#include "KernelAllocator.hpp"
#include "orbis/thread/types.hpp"
#include <algorithm>
#include <cstdint>
#include <mutex>
#include <pthread.h>
@ -175,6 +174,10 @@ public:
AudioOut *audioOut = nullptr;
uint sdkVersion{};
uint fwSdkVersion{};
uint safeMode{};
shared_mutex regMgrMtx;
kmap<std::uint32_t, std::uint32_t> regMgrInt;
private:
mutable pthread_mutex_t m_heap_mtx;

View file

@ -57,8 +57,8 @@ struct FileOps {
Thread *thread) = nullptr;
ErrorCode (*sendmsg)(orbis::File *file, msghdr *msg, sint flags,
Thread *thread) = nullptr;
ErrorCode (*recvfrom)(orbis::File *file, void *buf, size_t len,
sint flags, SocketAddress *from, uint32_t *fromlenaddr,
ErrorCode (*recvfrom)(orbis::File *file, void *buf, size_t len, sint flags,
SocketAddress *from, uint32_t *fromlenaddr,
Thread *thread) = nullptr;
ErrorCode (*recvmsg)(orbis::File *file, msghdr *msg, sint flags,
Thread *thread) = nullptr;
@ -75,11 +75,15 @@ struct FileOps {
struct File : RcBase {
shared_mutex mtx;
EventEmitter event;
Ref<EventEmitter> event;
const FileOps *ops = nullptr;
Ref<RcBase> device;
std::uint64_t nextOff = 0;
int flags = 0;
int mode = 0;
int hostFd = -1;
utils::kvector<Dirent> dirEntries;
bool noBlock() const { return (flags & 4) != 0; }
};
} // namespace orbis

View file

@ -16,7 +16,7 @@ struct Thread;
struct IpmiServer : RcBase {
struct IpmiPacketInfo {
ptr<void> userData;
ulong inputSize;
uint type;
uint clientKid;
ptr<void> eventHandler;
@ -26,6 +26,8 @@ struct IpmiServer : RcBase {
struct Packet {
IpmiPacketInfo info;
lwpid_t clientTid;
Ref<IpmiSession> session;
kvector<std::byte> message;
};
@ -36,6 +38,7 @@ struct IpmiServer : RcBase {
slong serverTid{};
};
kmap<std::uint32_t, std::uint32_t> tidToClientTid;
kstring name;
ptr<void> serverImpl;
ptr<void> eventHandler;
@ -51,24 +54,36 @@ struct IpmiServer : RcBase {
};
struct IpmiClient : RcBase {
struct MessageQueue {
shared_cv messageCv;
kdeque<kvector<std::byte>> messages;
};
struct AsyncResponse {
uint methodId;
sint errorCode;
kvector<kvector<std::byte>> data;
};
kstring name;
ptr<void> clientImpl;
ptr<void> userData;
Ref<IpmiSession> session;
shared_mutex mutex;
shared_cv sessionCv;
sint pid;
kdeque<kvector<std::byte>> messages;
Process *process;
kdeque<MessageQueue> messageQueues;
kdeque<EventFlag> eventFlags;
shared_cv messageCv;
kdeque<AsyncResponse> asyncResponses;
explicit IpmiClient(kstring name) : name(std::move(name)) {}
};
struct IpmiSession : RcBase {
struct MessageResponse {
struct SyncResponse {
sint errorCode;
kvector<std::byte> data;
std::uint32_t callerTid;
kvector<kvector<std::byte>> data;
};
ptr<void> sessionImpl;
@ -77,9 +92,9 @@ struct IpmiSession : RcBase {
Ref<IpmiServer> server;
shared_mutex mutex;
shared_cv responseCv;
kdeque<MessageResponse> messageResponses;
kdeque<SyncResponse> syncResponses;
shared_cv connectCv;
bool expectedOutput = false; // TODO: verify
uint expectedOutput{0};
sint connectionStatus{0};
};
@ -108,20 +123,19 @@ static_assert(sizeof(IpmiCreateClientConfig) == 0x150);
struct IpmiBufferInfo {
ptr<void> data;
uint64_t capacity;
uint64_t size;
};
struct IpmiDataInfo {
ptr<void> data;
uint64_t size;
uint64_t capacity; //?
};
static_assert(sizeof(IpmiBufferInfo) == 0x10);
static_assert(sizeof(IpmiDataInfo) == 0x18);
// static_assert(sizeof(IpmiBufferInfo) == 0x18);
// static_assert(sizeof(IpmiDataInfo) == 0x10);
struct IpmiSyncMessageHeader {
struct [[gnu::packed]] IpmiSyncMessageHeader {
orbis::ptr<void> sessionImpl;
orbis::uint pid;
orbis::uint methodId;
@ -129,10 +143,18 @@ struct IpmiSyncMessageHeader {
orbis::uint numOutData;
};
struct [[gnu::packed]] IpmiAsyncMessageHeader {
orbis::ptr<void> sessionImpl;
orbis::uint methodId;
orbis::uint pid;
orbis::uint numInData;
};
static_assert(sizeof(IpmiSyncMessageHeader) == 0x18);
ErrorCode ipmiCreateClient(Process *proc, void *clientImpl, const char *name,
const IpmiCreateClientConfig &config, Ref<IpmiClient> &result);
const IpmiCreateClientConfig &config,
Ref<IpmiClient> &result);
ErrorCode ipmiCreateServer(Process *proc, void *serverImpl, const char *name,
const IpmiCreateServerConfig &config,
Ref<IpmiServer> &result);
@ -162,9 +184,10 @@ SysResult sysIpmiSessionRespondSync(Thread *thread, ptr<uint> result, uint kid,
SysResult sysIpmiClientInvokeAsyncMethod(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiClientTryGetResult(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysImpiSessionRespondAsync(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientTryGetResult(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientGetMessage(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientTryGetMessage(Thread *thread, ptr<uint> result, uint kid,
@ -181,10 +204,15 @@ SysResult sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> result,
uint64_t paramsSz);
SysResult sysIpmiClientConnect(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSessionGetClientAppId(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiSessionGetUserData(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiServerGetName(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientGetName(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientWaitEventFlag(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientPollEventFlag(Thread *thread, ptr<uint> result, uint kid,

View file

@ -84,7 +84,7 @@ struct KNote {
~KNote();
};
struct EventEmitter {
struct EventEmitter : orbis::RcBase {
shared_mutex mutex;
std::set<KNote *, std::less<>, kallocator<KNote *>> notes;

View file

@ -1,6 +1,8 @@
#include "orbis-config.hpp"
#include <orbis/error.hpp>
#include <orbis/thread.hpp>
#include <orbis/time.hpp>
#include <orbis/module/ModuleHandle.hpp>
#include <orbis/thread/cpuset.hpp>
#include <orbis/thread/types.hpp>
namespace orbis {
using acl_type_t = sint;
@ -11,17 +13,24 @@ using cpuwhich_t = sint;
using cpulevel_t = sint;
using SceKernelModule = ModuleHandle;
struct Thread;
struct AuthInfo;
struct MemoryProtection;
struct ModuleInfo;
struct ModuleInfoEx;
struct KEvent;
struct timespec;
struct timesec;
struct timezone;
struct timeval;
struct Stat;
struct stack_t;
struct IoVec;
struct BatchMapEntry;
struct UContext;
struct SigSet;
struct SigAction;
struct SocketAddress;
SysResult nosys(Thread *thread);
@ -29,7 +38,7 @@ SysResult sys_exit(Thread *thread, sint status);
SysResult sys_fork(Thread *thread);
SysResult sys_read(Thread *thread, sint fd, ptr<void> buf, size_t nbyte);
SysResult sys_write(Thread *thread, sint fd, ptr<const void> buf, size_t nbyte);
SysResult sys_open(Thread *thread, ptr<char> path, sint flags, sint mode);
SysResult sys_open(Thread *thread, ptr<const char> path, sint flags, sint mode);
SysResult sys_close(Thread *thread, sint fd);
SysResult sys_wait4(Thread *thread, sint pid, ptr<sint> status, sint options,
ptr<struct rusage> rusage);
@ -125,15 +134,14 @@ SysResult sys_bind(Thread *thread, sint s, caddr_t name, sint namelen);
SysResult sys_setsockopt(Thread *thread, sint s, sint level, sint name,
caddr_t val, sint valsize);
SysResult sys_listen(Thread *thread, sint s, sint backlog);
SysResult sys_gettimeofday(Thread *thread, ptr<orbis::timeval> tp,
ptr<orbis::timezone> tzp);
SysResult sys_gettimeofday(Thread *thread, ptr<timeval> tp, ptr<timezone> tzp);
SysResult sys_getrusage(Thread *thread, sint who, ptr<struct rusage> rusage);
SysResult sys_getsockopt(Thread *thread, sint s, sint level, sint name,
caddr_t val, ptr<sint> avalsize);
SysResult sys_readv(Thread *thread, sint fd, ptr<IoVec> iovp, uint iovcnt);
SysResult sys_writev(Thread *thread, sint fd, ptr<IoVec> iovp, uint iovcnt);
SysResult sys_settimeofday(Thread *thread, ptr<struct timeval> tp,
ptr<orbis::timezone> tzp);
ptr<timezone> tzp);
SysResult sys_fchown(Thread *thread, sint fd, sint uid, sint gid);
SysResult sys_fchmod(Thread *thread, sint fd, sint mode);
SysResult sys_setreuid(Thread *thread, sint ruid, sint euid);
@ -230,8 +238,8 @@ SysResult sys_ktimer_settime(Thread *thread, sint timerid, sint flags,
SysResult sys_ktimer_gettime(Thread *thread, sint timerid,
ptr<struct itimerspec> value);
SysResult sys_ktimer_getoverrun(Thread *thread, sint timerid);
SysResult sys_nanosleep(Thread *thread, cptr<orbis::timespec> rqtp,
ptr<orbis::timespec> rmtp);
SysResult sys_nanosleep(Thread *thread, cptr<timespec> rqtp,
ptr<timespec> rmtp);
SysResult sys_ntp_gettime(Thread *thread, ptr<struct ntptimeval> ntvp);
SysResult sys_minherit(Thread *thread, ptr<void> addr, size_t len,
sint inherit);
@ -305,14 +313,14 @@ SysResult sys_jail(Thread *thread, ptr<struct jail> jail);
SysResult sys_nnpfs_syscall(Thread *thread, sint operation, ptr<char> a_pathP,
sint opcode, ptr<void> a_paramsP,
sint a_followSymlinks);
SysResult sys_sigprocmask(Thread *thread, sint how, ptr<uint64_t> set,
ptr<uint64_t> oset);
SysResult sys_sigsuspend(Thread *thread, ptr<const struct sigset> set);
SysResult sys_sigpending(Thread *thread, ptr<struct sigset> set);
SysResult sys_sigtimedwait(Thread *thread, ptr<const struct sigset> set,
SysResult sys_sigprocmask(Thread *thread, sint how, ptr<SigSet> set,
ptr<SigSet> oset);
SysResult sys_sigsuspend(Thread *thread, ptr<const SigSet> set);
SysResult sys_sigpending(Thread *thread, ptr<SigSet> set);
SysResult sys_sigtimedwait(Thread *thread, ptr<const SigSet> set,
ptr<struct siginfo> info,
ptr<const timespec> timeout);
SysResult sys_sigwaitinfo(Thread *thread, ptr<const struct sigset> set,
SysResult sys_sigwaitinfo(Thread *thread, ptr<const SigSet> set,
ptr<struct siginfo> info);
SysResult sys___acl_get_file(Thread *thread, ptr<char> path, acl_type_t type,
ptr<struct acl> aclp);
@ -412,13 +420,13 @@ SysResult sys_extattr_delete_link(Thread *thread, ptr<const char> path,
sint attrnamespace, ptr<const char> attrname);
SysResult sys___mac_execve(Thread *thread, ptr<char> fname, ptr<ptr<char>> argv,
ptr<ptr<char>> envv, ptr<struct mac> mac_p);
SysResult sys_sigaction(Thread *thread, sint sig, ptr<struct sigaction> act,
ptr<struct sigaction> oact);
SysResult sys_sigreturn(Thread *thread, ptr<struct ucontext> sigcntxp);
SysResult sys_getcontext(Thread *thread, ptr<struct ucontext> ucp);
SysResult sys_setcontext(Thread *thread, ptr<struct ucontext> ucp);
SysResult sys_swapcontext(Thread *thread, ptr<struct ucontext> oucp,
ptr<struct ucontext> ucp);
SysResult sys_sigaction(Thread *thread, sint sig, ptr<SigAction> act,
ptr<SigAction> oact);
SysResult sys_sigreturn(Thread *thread, ptr<UContext> sigcntxp);
SysResult sys_getcontext(Thread *thread, ptr<UContext> ucp);
SysResult sys_setcontext(Thread *thread, ptr<UContext> ucp);
SysResult sys_swapcontext(Thread *thread, ptr<UContext> oucp,
ptr<UContext> ucp);
SysResult sys_swapoff(Thread *thread, ptr<const char> name);
SysResult sys___acl_get_link(Thread *thread, ptr<const char> path,
acl_type_t type, ptr<struct acl> aclp);
@ -428,10 +436,9 @@ SysResult sys___acl_delete_link(Thread *thread, ptr<const char> path,
acl_type_t type);
SysResult sys___acl_aclcheck_link(Thread *thread, ptr<const char> path,
acl_type_t type, ptr<struct acl> aclp);
SysResult sys_sigwait(Thread *thread, ptr<const struct sigset> set,
ptr<sint> sig);
SysResult sys_thr_create(Thread *thread, ptr<struct ucontext> ctxt,
ptr<slong> arg, sint flags);
SysResult sys_sigwait(Thread *thread, ptr<const SigSet> set, ptr<sint> sig);
SysResult sys_thr_create(Thread *thread, ptr<UContext> ctxt, ptr<slong> arg,
sint flags);
SysResult sys_thr_exit(Thread *thread, ptr<slong> state);
SysResult sys_thr_self(Thread *thread, ptr<slong> id);
SysResult sys_thr_kill(Thread *thread, slong id, sint sig);
@ -636,8 +643,9 @@ SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value,
ptr<sint> pNumWaitThreads);
SysResult sys_query_memory_protection(Thread *thread, ptr<void> address,
ptr<MemoryProtection> protection);
SysResult sys_batch_map(Thread *thread, sint unk, sint flags, ptr<BatchMapEntry> entries,
sint entriesCount, ptr<sint> processedCount);
SysResult sys_batch_map(Thread *thread, sint unk, sint flags,
ptr<BatchMapEntry> entries, sint entriesCount,
ptr<sint> processedCount);
SysResult sys_osem_create(Thread *thread, ptr<const char[32]> name, uint attrs,
sint initCount, sint maxCount);
SysResult sys_osem_delete(Thread *thread, sint id);
@ -746,15 +754,16 @@ SysResult sys_physhm_unlink(Thread *thread /* TODO */);
SysResult sys_resume_internal_hdd(Thread *thread /* TODO */);
SysResult sys_thr_suspend_ucontext(Thread *thread, lwpid_t tid);
SysResult sys_thr_resume_ucontext(Thread *thread, lwpid_t tid);
SysResult sys_thr_get_ucontext(Thread *thread, lwpid_t tid, ptr<UContext> context);
SysResult sys_thr_set_ucontext(Thread *thread, lwpid_t tid, ptr<UContext> context);
SysResult sys_thr_get_ucontext(Thread *thread, lwpid_t tid,
ptr<UContext> context);
SysResult sys_thr_set_ucontext(Thread *thread, lwpid_t tid,
ptr<UContext> context);
SysResult sys_set_timezone_info(Thread *thread /* TODO */);
SysResult sys_set_phys_fmem_limit(Thread *thread /* TODO */);
SysResult sys_utc_to_localtime(Thread *thread, int64_t time, int64_t *localtime,
orbis::timesec *_sec, int *_dst_sec);
timesec *_sec, int *_dst_sec);
SysResult sys_localtime_to_utc(Thread *thread, int64_t time, uint unk,
int64_t *ptime, orbis::timesec *_sec,
int *_dst_sec);
int64_t *ptime, timesec *_sec, int *_dst_sec);
SysResult sys_set_uevt(Thread *thread /* TODO */);
SysResult sys_get_cpu_usage_proc(Thread *thread /* TODO */);
SysResult sys_get_map_statistics(Thread *thread /* TODO */);

View file

@ -66,6 +66,7 @@ struct Process final {
bool isInSandbox = false;
EventEmitter event;
std::uint32_t sdkVersion = -1;
std::uint64_t nextTlsSlot = 1;
std::uint64_t lastTlsOffset = 0;
@ -81,6 +82,8 @@ struct Process final {
utils::kmap<void *, utils::kstring> namedObjNames;
utils::OwningIdMap<NamedObjInfo, uint, 65535, 1> namedObjIds;
utils::kmap<std::int32_t, SigAction> sigActions;
// Named memory ranges for debugging
utils::shared_mutex namedMemMutex;
utils::kmap<NamedMemoryRange, utils::kstring> namedMem;

View file

@ -12,6 +12,7 @@ struct timespec;
struct File;
struct MemoryProtection;
struct IoVec;
struct UContext;
struct ProcessOps {
SysResult (*mmap)(Thread *thread, caddr_t addr, size_t len, sint prot,
@ -64,7 +65,7 @@ struct ProcessOps {
uint64_t arg3);
SysResult (*dynlib_unload_prx)(Thread *thread, ModuleHandle handle);
SysResult (*thr_create)(Thread *thread, ptr<struct ucontext> ctxt,
SysResult (*thr_create)(Thread *thread, ptr<UContext> ctxt,
ptr<slong> arg, sint flags);
SysResult (*thr_new)(Thread *thread, ptr<thr_param> param, sint param_size);
SysResult (*thr_exit)(Thread *thread, ptr<slong> state);

View file

@ -19,5 +19,6 @@ enum class RegisterId {
rax,
rsp,
rflags,
rip,
};
} // namespace orbis

View file

@ -4,12 +4,16 @@
#include "orbis-config.hpp"
#include "types.hpp"
#include "../KernelAllocator.hpp"
#include "../ucontext.hpp"
#include "../utils/SharedCV.hpp"
#include "../utils/SharedMutex.hpp"
#include <atomic>
#include <thread>
namespace orbis {
struct Process;
struct Thread {
utils::shared_mutex mtx;
Process *tproc = nullptr;
@ -21,8 +25,14 @@ struct Thread {
uint64_t gsBase{};
char name[32]{};
uint64_t sigMask[4] = {0x7fff'ffff, 0};
SigSet sigMask = {0x7fff'ffff, ~0u, ~0u, ~0u};
utils::shared_mutex suspend_mtx;
utils::shared_cv suspend_cv;
kdeque<int> signalQueue;
kvector<UContext> sigReturns;
std::atomic<unsigned> suspended{0};
std::int64_t hostTid = -1;
lwpid_t tid = -1;
ThreadState state = ThreadState::INACTIVE;
std::thread handle;
@ -35,6 +45,10 @@ struct Thread {
// Print backtrace
void where();
void suspend();
void resume();
void sendSignal(int signo);
// FIXME: implement thread destruction
void incRef() {}
void decRef() {}

View file

@ -54,7 +54,20 @@ struct Stack {
};
struct SigSet {
ulong bits[2];
static constexpr auto min = 1;
static constexpr auto max = 128;
uint bits[4];
bool test(unsigned signal) const {
return (bits[(signal - 1) >> 5] & (1 << ((signal - 1) & 31))) != 0;
}
void set(unsigned signal) {
bits[(signal - 1) >> 5] |= (1 << ((signal - 1) & 31));
}
void clear(unsigned signal) {
bits[(signal - 1) >> 5] &= ~(1 << ((signal - 1) & 31));
}
};
struct UContext {
@ -67,4 +80,87 @@ struct UContext {
sint spare[4];
sint unk1[3];
};
static_assert(sizeof(UContext) == 0x500);
enum Signal {
kSigHup = 1,
kSigInt = 2,
kSigQuit = 3,
kSigIll = 4,
kSigTrap = 5,
kSigAbrt = 6,
kSigEmt = 7,
kSigFpe = 8,
kSigKill = 9,
kSigBus = 10,
kSigSegv = 11,
kSigSys = 12,
kSigPipe = 13,
kSigAlrm = 14,
kSigUrg = 16,
kSigStop = 17,
kSigTstp = 18,
kSigCont = 19,
kSigChld = 20,
kSigTtin = 21,
kSigTtou = 22,
kSigIo = 23,
kSigXcpu = 24,
kSigXfsz = 25,
kSigVtalrm = 26,
kSigProf = 27,
kSigWinch = 28,
kSigInfo = 29,
kSigUsr1 = 30,
kSigUsr2 = 31,
kSigThr = 32,
};
struct SigAction {
ptr<void(int32_t, void *, void *)> handler;
sint flags;
SigSet mask;
};
union SigVal {
sint integer;
ptr<void> pointer;
};
struct SigInfo {
sint signo;
sint errno_;
sint code;
sint pid;
slong uid;
sint status;
ptr<void> addr;
SigVal value;
union {
struct {
sint trapno;
} fault;
struct {
sint timerid;
sint overrun;
} timer;
struct {
sint mqd;
} mesgq;
struct {
slong band;
} poll;
struct {
slong spare1;
sint spare2[7];
} spare;
} reason;
};
} // namespace orbis

View file

@ -34,7 +34,7 @@ protected:
}
// Internal waiting function
void impl_wait(shared_mutex &mutex, unsigned _val,
int impl_wait(shared_mutex &mutex, unsigned _val,
std::uint64_t usec_timeout) noexcept;
// Try to notify up to _count threads
@ -43,14 +43,14 @@ protected:
public:
constexpr shared_cv() = default;
void wait(shared_mutex &mutex, std::uint64_t usec_timeout = -1) noexcept {
int wait(shared_mutex &mutex, std::uint64_t usec_timeout = -1) noexcept {
const unsigned _val = add_waiter();
if (!_val) {
return;
return 0;
}
mutex.unlock();
impl_wait(mutex, _val, usec_timeout);
return impl_wait(mutex, _val, usec_timeout);
}
// Wake one thread

View file

@ -20,7 +20,7 @@ class shared_mutex final {
void impl_lock_shared(unsigned val);
void impl_unlock_shared(unsigned old);
void impl_wait();
int impl_wait();
void impl_signal();
void impl_lock(unsigned val);
void impl_unlock(unsigned old);