blob: e9ce52dbe8199e3b8dc59d72f878ff526dc1c962 [file]
//===-- Linux implementation of semctl ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "src/sys/sem/semctl.h"
#include "hdr/errno_macros.h"
#include "hdr/sys_ipc_macros.h"
#include "hdr/sys_sem_macros.h"
#include "hdr/types/struct_semid_ds.h"
#include "hdr/types/struct_seminfo.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/semctl.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include <stdarg.h>
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, semctl, (int semid, int semnum, int cmd, ...)) {
// used to parse the fourth varargs argument
// its expected to be explicitly declared by application as an union type:
// union semun {
// int val;
// struct semid_ds *buf;
// unsigned short *array;
// struct seminfo *__buf; (* linux specific *)
// } arg;
unsigned long cmd_arg = 0;
// parse cmd_arg based on the flags
switch (cmd) {
// does not use the vargs
case IPC_RMID:
case GETVAL:
case GETPID:
case GETNCNT:
case GETZCNT:
break;
// use vargs as int, semun->val
case SETVAL: {
va_list vargs;
va_start(vargs, cmd);
cmd_arg = static_cast<unsigned long>(va_arg(vargs, int));
va_end(vargs);
break;
}
// use vargs as semid_ds*, semun->buf
case IPC_SET:
case IPC_STAT:
case SEM_STAT:
case SEM_STAT_ANY: {
va_list vargs;
va_start(vargs, cmd);
cmd_arg = reinterpret_cast<unsigned long>(va_arg(vargs, struct semid_ds *));
va_end(vargs);
break;
}
// use vargs as short*, semun->array
case GETALL:
case SETALL: {
va_list vargs;
va_start(vargs, cmd);
cmd_arg = reinterpret_cast<unsigned long>(va_arg(vargs, unsigned short *));
va_end(vargs);
break;
}
// linux specific, use vargs as seminfo*, semun->__buf
case IPC_INFO:
case SEM_INFO: {
va_list vargs;
va_start(vargs, cmd);
cmd_arg = reinterpret_cast<unsigned long>(va_arg(vargs, struct seminfo *));
va_end(vargs);
break;
}
// unrecognized flags
default:
libc_errno = EINVAL;
return -1;
}
auto result = linux_syscalls::semctl(semid, semnum, cmd, cmd_arg);
if (!result) {
libc_errno = result.error();
return -1;
}
return result.value();
}
} // namespace LIBC_NAMESPACE_DECL