blob: 1dd38f773004e1579fef9e78689a25e9161e3255 [file] [log] [blame]
//===-- 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/syscall.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include <stdarg.h>
#include <sys/syscall.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;
}
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_semctl, semid, semnum, cmd,
cmd_arg);
if (ret < 0) {
libc_errno = -ret;
return -1;
}
return ret;
}
} // namespace LIBC_NAMESPACE_DECL