android13/external/ltp/testcases/kernel/syscalls/ipc/semctl/semctl01.c

317 lines
6.4 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) International Business Machines Corp., 2001
*/
/*\
* [Description]
*
* Test the 13 possible semctl() commands
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include "tst_safe_sysv_ipc.h"
#include "tst_test.h"
#include "lapi/sem.h"
#include "libnewipc.h"
#define INCVAL 2
#define NEWMODE 066
#define NCHILD 5
#define SEMUN_CAST (union semun)
static int sem_id = -1;
static int sem_index;
static struct semid_ds buf;
static struct seminfo ipc_buf;
static unsigned short array[PSEMS];
static struct sembuf sops;
static int pid_arr[NCHILD];
static void kill_all_children(void)
{
int j;
for (j = 0; j < NCHILD; j++)
SAFE_KILL(pid_arr[j], SIGKILL);
for (j = 0; j < NCHILD; j++)
SAFE_WAIT(NULL);
}
static void func_stat(void)
{
if (buf.sem_nsems == PSEMS && buf.sem_perm.mode == (SEM_RA))
tst_res(TPASS, "buf.sem_nsems and buf.sem_perm.mode are correct");
else
tst_res(TFAIL, "semaphore STAT info is incorrect");
}
static void set_setup(void)
{
buf.sem_perm.mode = SEM_RA | NEWMODE;
}
static void func_set(void)
{
SAFE_SEMCTL(sem_id, 0, IPC_STAT, (union semun)&buf);
if (buf.sem_perm.mode == (SEM_RA | NEWMODE))
tst_res(TPASS, "buf.sem_perm.mode is correct");
else
tst_res(TFAIL, "semaphore mode info is incorrect");
}
static void func_gall(void)
{
int i;
for (i = 0; i < PSEMS; i++) {
if (array[i] != 0) {
tst_res(TFAIL, "semaphore %d has unexpected value", i);
return;
}
}
tst_res(TPASS, "semaphores have expected values");
}
static void child_cnt(void)
{
sops.sem_num = 4;
sops.sem_flg = 0;
/*
* Do a semop that will cause the child to sleep.
* The child process will be killed in the func_ncnt
* routine which should cause an error to be return
* by the semop() call.
*/
if (semop(sem_id, &sops, 1) != -1)
tst_brk(TBROK, "semop succeeded - cnt_setup");
}
static void cnt_setup(int opval)
{
int pid, i;
sops.sem_num = 4;
sops.sem_flg = 0;
/*
* if seting up for GETZCNT, the semaphore value needs to be positive
*/
if (opval == 0) {
sops.sem_op = 1;
SAFE_SEMOP(sem_id, &sops, 1);
}
sops.sem_op = opval;
for (i = 0; i < NCHILD; i++) {
pid = SAFE_FORK();
if (pid == 0) {
child_cnt();
} else {
TST_PROCESS_STATE_WAIT(pid, 'S', 0);
pid_arr[i] = pid;
}
}
}
static void func_cnt(int rval)
{
if (rval == NCHILD)
tst_res(TPASS, "number of sleeping processes is correct");
else
tst_res(TFAIL, "number of sleeping processes is not correct");
}
static void child_pid(void)
{
sops.sem_num = 2;
sops.sem_op = 1;
sops.sem_flg = 0;
/*
* Do a semop that will increment the semaphore.
*/
SAFE_SEMOP(sem_id, &sops, 1);
exit(0);
}
static void pid_setup(void)
{
int pid;
pid = SAFE_FORK();
if (pid == 0) {
child_pid();
} else {
pid_arr[2] = pid;
TST_PROCESS_STATE_WAIT(pid, 'Z', 0);
}
}
static void func_pid(int rval)
{
if (rval == pid_arr[2])
tst_res(TPASS, "last pid value is correct");
else
tst_res(TFAIL, "last pid value is not correct");
}
static void func_gval(int rval)
{
/*
* This is a simple test. The semaphore value should be equal
* to ONE as it was set in the last test (GETPID).
*/
if (rval == 1)
tst_res(TPASS, "semaphore value is correct");
else
tst_res(TFAIL, "semaphore value is not correct");
}
static void sall_setup(void)
{
int i;
for (i = 0; i < PSEMS; i++) {
array[i] = 3;
}
}
static void func_sall(void)
{
int i;
unsigned short rarray[PSEMS];
SAFE_SEMCTL(sem_id, 0, GETALL, (union semun)rarray);
for (i = 0; i < PSEMS; i++) {
if (array[i] != rarray[i]) {
tst_res(TFAIL, "semaphore values are not correct");
return;
}
}
tst_res(TPASS, "semaphore values are correct");
}
static void func_sval(void)
{
int semv;
union semun arr;
semv = SAFE_SEMCTL(sem_id, 4, GETVAL, arr);
if (semv != INCVAL)
tst_res(TFAIL, "semaphore value is not what was set");
else
tst_res(TPASS, "semaphore value is correct");
}
static void func_rmid(void)
{
TST_EXP_FAIL(semop(sem_id, &sops, 1), EINVAL, "semaphore appears to be removed");
sem_id = -1;
}
static void func_iinfo(int hidx)
{
if (hidx >= 0) {
sem_index = hidx;
tst_res(TPASS, "the highest index is correct");
} else {
sem_index = 0;
tst_res(TFAIL, "the highest index is incorrect");
}
}
static void func_sinfo(void)
{
if (ipc_buf.semusz < 1)
tst_res(TFAIL, "number of semaphore sets is incorrect");
else
tst_res(TPASS, "number of semaphore sets is correct");
}
static void func_sstat(int semidx)
{
if (semidx >= 0)
tst_res(TPASS, "id of the semaphore set is correct");
else
tst_res(TFAIL, "id of the semaphore set is incorrect");
}
static struct tcases {
int *semid;
int semnum;
int cmd;
void (*func_test) ();
union semun arg;
void (*func_setup) ();
} tests[] = {
{&sem_id, 0, IPC_STAT, func_stat, SEMUN_CAST & buf, NULL},
{&sem_id, 0, IPC_SET, func_set, SEMUN_CAST & buf, set_setup},
{&sem_id, 0, GETALL, func_gall, SEMUN_CAST array, NULL},
{&sem_id, 4, GETNCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
{&sem_id, 2, GETPID, func_pid, SEMUN_CAST & buf, pid_setup},
{&sem_id, 2, GETVAL, func_gval, SEMUN_CAST & buf, NULL},
{&sem_id, 4, GETZCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
{&sem_id, 0, SETALL, func_sall, SEMUN_CAST array, sall_setup},
{&sem_id, 4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL},
{&sem_id, 0, IPC_INFO, func_iinfo, SEMUN_CAST & ipc_buf, NULL},
{&sem_id, 0, SEM_INFO, func_sinfo, SEMUN_CAST & ipc_buf, NULL},
{&sem_index, 0, SEM_STAT, func_sstat, SEMUN_CAST & buf, NULL},
{&sem_id, 0, IPC_RMID, func_rmid, SEMUN_CAST & buf, NULL},
};
static void verify_semctl(unsigned int n)
{
struct tcases *tc = &tests[n];
int rval;
if (sem_id == -1)
sem_id = SAFE_SEMGET(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
if (tc->func_setup) {
switch (tc->cmd) {
case GETNCNT:
tc->func_setup(-1);
break;
case GETZCNT:
tc->func_setup(0);
break;
default:
tc->func_setup();
break;
}
}
rval = SAFE_SEMCTL(*(tc->semid), tc->semnum, tc->cmd, tc->arg);
switch (tc->cmd) {
case GETNCNT:
case GETZCNT:
case GETPID:
case GETVAL:
case IPC_INFO:
case SEM_STAT:
tc->func_test(rval);
break;
default:
tc->func_test();
break;
}
if (tc->cmd == GETNCNT || tc->cmd == GETZCNT)
kill_all_children();
}
static void cleanup(void)
{
if (sem_id >= 0)
SAFE_SEMCTL(sem_id, 0, IPC_RMID);
}
static struct tst_test test = {
.cleanup = cleanup,
.test = verify_semctl,
.tcnt = ARRAY_SIZE(tests),
.forks_child = 1,
};