* [LTP] [PATCH v2] semctl: updates for multi worker testing.
@ 2026-04-14 16:49 Stephen Bertram via ltp
2026-04-14 17:15 ` [LTP] " linuxtestproject.agent
2026-07-20 22:49 ` [LTP] [PATCH v3] semctl01: tolerate SEM_STAT races under parallel LTP runs Stephen Bertram via ltp
0 siblings, 2 replies; 8+ messages in thread
From: Stephen Bertram via ltp @ 2026-04-14 16:49 UTC (permalink / raw)
To: ltp; +Cc: Stephen Bertram
Changed semctl01, which required updates to
reduce interference and provide an allowance
for EINVAL and EIDRM failures.
Signed-off-by: Stephen Bertram <sbertram@redhat.com>
---
.../kernel/syscalls/ipc/semctl/semctl01.c | 91 +++++++++++++------
1 file changed, 61 insertions(+), 30 deletions(-)
diff --git a/testcases/kernel/syscalls/ipc/semctl/semctl01.c b/testcases/kernel/syscalls/ipc/semctl/semctl01.c
index 5bd675ab6..25c7ebc65 100644
--- a/testcases/kernel/syscalls/ipc/semctl/semctl01.c
+++ b/testcases/kernel/syscalls/ipc/semctl/semctl01.c
@@ -8,6 +8,7 @@
#define _GNU_SOURCE
#include <stdlib.h>
+#include <pthread.h>
#include "tst_safe_sysv_ipc.h"
#include "tst_test.h"
#include "lapi/sem.h"
@@ -18,14 +19,16 @@
#define NCHILD 5
#define SEMUN_CAST (union semun)
-static int sem_id = -1;
-static int sem_index;
+static __thread int sem_id = -1;
+static __thread 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 pthread_mutex_t sem_stat_lock = PTHREAD_MUTEX_INITIALIZER;
+
static void kill_all_children(void)
{
int j;
@@ -243,28 +246,36 @@ static struct tcases {
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},
+ {NULL, 0, IPC_STAT, func_stat, SEMUN_CAST & buf, NULL},
+ {NULL, 0, IPC_SET, func_set, SEMUN_CAST & buf, set_setup},
+ {NULL, 0, GETALL, func_gall, SEMUN_CAST array, NULL},
+ {NULL, 4, GETNCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {NULL, 2, GETPID, func_pid, SEMUN_CAST & buf, pid_setup},
+ {NULL, 2, GETVAL, func_gval, SEMUN_CAST & buf, NULL},
+ {NULL, 4, GETZCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {NULL, 0, SETALL, func_sall, SEMUN_CAST array, sall_setup},
+ {NULL, 4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL},
+ {NULL, 0, IPC_INFO, func_iinfo, SEMUN_CAST & ipc_buf, NULL},
+ {NULL, 0, SEM_INFO, func_sinfo, SEMUN_CAST & ipc_buf, NULL},
+ {NULL, 0, SEM_STAT, func_sstat, SEMUN_CAST & buf, NULL},
+ {NULL, 0, IPC_RMID, func_rmid, SEMUN_CAST & buf, NULL},
};
static void verify_semctl(unsigned int n)
{
struct tcases *tc = &tests[n];
- int rval;
+ int rval, sid;
+ int retries = 5;
+
+ /* Resolve sem id: SEM_STAT uses sem_index, others use sem_id */
+ if (tc->cmd == SEM_STAT)
+ sid = sem_index;
+ else {
+ sid = sem_id;
+ if (sid == -1)
+ sem_id = sid = SAFE_SEMGET(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
+ }
- 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:
@@ -279,21 +290,41 @@ static void verify_semctl(unsigned int n)
}
}
- 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:
+ /* SEM_STAT: get index under lock, call SEM_STAT without lock, retry on EIDRM and EINVAL */
+ if (tc->cmd == SEM_STAT) {
+ do {
+ pthread_mutex_lock(&sem_stat_lock);
+ sem_index = semctl(0, 0, IPC_INFO, (union semun)&ipc_buf);
+ pthread_mutex_unlock(&sem_stat_lock);
+ if (sem_index < 0)
+ tst_brk(TBROK | TERRNO, "semctl(0, 0, IPC_INFO)");
+ rval = semctl(sem_index, 0, tc->cmd, tc->arg);
+ if (rval >= 0)
+ break;
+ if ((errno != EIDRM && errno != EINVAL) || --retries <= 0)
+ tst_brk(TBROK | TERRNO, "semctl(SEM_STAT)");
+ } while (1);
tc->func_test(rval);
- break;
- default:
+ } else if (tc->cmd == IPC_RMID) {
+ pthread_mutex_lock(&sem_stat_lock);
+ SAFE_SEMCTL(sid, tc->semnum, tc->cmd, tc->arg);
+ pthread_mutex_unlock(&sem_stat_lock);
tc->func_test();
- break;
+ } else {
+ rval = SAFE_SEMCTL(sid, tc->semnum, tc->cmd, tc->arg);
+ switch (tc->cmd) {
+ case GETNCNT:
+ case GETZCNT:
+ case GETPID:
+ case GETVAL:
+ case IPC_INFO:
+ tc->func_test(rval);
+ break;
+ default:
+ tc->func_test();
+ break;
+ }
}
-
if (tc->cmd == GETNCNT || tc->cmd == GETZCNT)
kill_all_children();
}
--
2.53.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [LTP] semctl: updates for multi worker testing.
2026-04-14 16:49 [LTP] [PATCH v2] semctl: updates for multi worker testing Stephen Bertram via ltp
@ 2026-04-14 17:15 ` linuxtestproject.agent
2026-07-20 22:49 ` [LTP] [PATCH v3] semctl01: tolerate SEM_STAT races under parallel LTP runs Stephen Bertram via ltp
1 sibling, 0 replies; 8+ messages in thread
From: linuxtestproject.agent @ 2026-04-14 17:15 UTC (permalink / raw)
To: Stephen Bertram; +Cc: ltp
Hi Stephen,
On Tue, 14 Apr 2026, Stephen Bertram wrote:
> semctl: updates for multi worker testing.
>
> Changed semctl01, which required updates to
> reduce interference and provide an allowance
> for EINVAL and EIDRM failures.
The body should say *why* multi-worker support is needed — what harness
or runner exercises this in parallel, or what failure prompted the change.
> -static int sem_id = -1;
> -static int sem_index;
> +static __thread int sem_id = -1;
> +static __thread 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];
buf, ipc_buf, array, sops, pid_arr are still plain globals. Making only
sem_id/sem_index TLS leaves all the helper functions that read/write
these globals unsafe for concurrent use, so the parallelisation is
incomplete.
[...]
> + if (sid == -1)
> + sem_id = sid = SAFE_SEMGET(IPC_PRIVATE, PSEMS,
> + IPC_CREAT | IPC_EXCL | SEM_RA);
cleanup() runs in the main thread and only sees the main thread's TLS
sem_id. Worker threads that hit this path will leak their semaphore sets.
Either track all allocated IDs in a shared, mutex-protected list, or drop
__thread and keep the test single-threaded.
Also note struct tcases::semid is now always NULL and never read; the
field can be removed.
---
Note:
Our agent completed the review of the patch. The full review can be
found at: https://patchwork.ozlabs.org/project/ltp/list/?series=499874
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread
* [LTP] [PATCH v3] semctl01: tolerate SEM_STAT races under parallel LTP runs
2026-04-14 16:49 [LTP] [PATCH v2] semctl: updates for multi worker testing Stephen Bertram via ltp
2026-04-14 17:15 ` [LTP] " linuxtestproject.agent
@ 2026-07-20 22:49 ` Stephen Bertram via ltp
2026-07-20 23:13 ` [LTP] " linuxtestproject.agent
2026-07-20 23:56 ` [LTP] [PATCH v4] " Stephen Bertram via ltp
1 sibling, 2 replies; 8+ messages in thread
From: Stephen Bertram via ltp @ 2026-07-20 22:49 UTC (permalink / raw)
To: ltp; +Cc: Stephen Bertram
When multiple LTP workers run IPC tests concurrently, SEM_STAT can fail
with EIDRM/EINVAL because the index from IPC_INFO can disappear before
SEM_STAT runs. Retry a few times instead of treating that as TBROK.
The test remains single-threaded; shared globals are intentional.
Test: ./kirk -w 4 -f syscalls_32 -p semctl01 -i 1000
Results summary before:
runtime: 997.690s
passed 415980
failed 0
broken 10
skipped 0
warnings 0
Results summary after:
runtime: 998.593s
passed 416000
failed 0
broken 0
skipped 0
warnings 0
Assisted-by: Cursor
Signed-off-by: Stephen Bertram <sbertram@redhat.com>
---
testcases/kernel/syscalls/semctl/semctl01.c | 90 ++++++++++++++-------
1 file changed, 61 insertions(+), 29 deletions(-)
diff --git a/testcases/kernel/syscalls/semctl/semctl01.c b/testcases/kernel/syscalls/semctl/semctl01.c
index 5bd675ab6..e5056e8e3 100644
--- a/testcases/kernel/syscalls/semctl/semctl01.c
+++ b/testcases/kernel/syscalls/semctl/semctl01.c
@@ -236,35 +236,58 @@ static void func_sstat(int semidx)
}
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},
+ {0, IPC_STAT, func_stat, SEMUN_CAST & buf, NULL},
+ {0, IPC_SET, func_set, SEMUN_CAST & buf, set_setup},
+ {0, GETALL, func_gall, SEMUN_CAST array, NULL},
+ {4, GETNCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {2, GETPID, func_pid, SEMUN_CAST & buf, pid_setup},
+ {2, GETVAL, func_gval, SEMUN_CAST & buf, NULL},
+ {4, GETZCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {0, SETALL, func_sall, SEMUN_CAST array, sall_setup},
+ {4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL},
+ {0, IPC_INFO, func_iinfo, SEMUN_CAST & ipc_buf, NULL},
+ {0, SEM_INFO, func_sinfo, SEMUN_CAST & ipc_buf, NULL},
+ {0, SEM_STAT, func_sstat, SEMUN_CAST & buf, NULL},
+ {0, IPC_RMID, func_rmid, SEMUN_CAST & buf, NULL},
};
+/*
+ * SEM_STAT takes an ipc idr index. Under parallel IPC tests that index can
+ * vanish between IPC_INFO and SEM_STAT (EIDRM/EINVAL). Refresh and retry.
+ */
+static int do_sem_stat(union semun arg)
+{
+ int idx, rval;
+ unsigned int retries = 5;
+
+ do {
+ idx = semctl(0, 0, IPC_INFO, (union semun)&ipc_buf);
+ if (idx < 0)
+ tst_brk(TBROK | TERRNO, "semctl(0, 0, IPC_INFO)");
+ rval = semctl(idx, 0, SEM_STAT, arg);
+ if (rval >= 0) {
+ sem_index = idx;
+ return rval;
+ }
+ if (errno != EIDRM && errno != EINVAL)
+ tst_brk(TBROK | TERRNO, "semctl(SEM_STAT)");
+ } while (--retries);
+
+ tst_brk(TBROK | TERRNO, "semctl(SEM_STAT) still failing after retries");
+ return -1;
+}
+
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:
@@ -279,25 +302,33 @@ static void verify_semctl(unsigned int n)
}
}
- 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:
+ if (tc->cmd == SEM_STAT) {
+ rval = do_sem_stat(tc->arg);
tc->func_test(rval);
- break;
- default:
- tc->func_test();
- break;
+ } else {
+ rval = SAFE_SEMCTL(sem_id, tc->semnum, tc->cmd, tc->arg);
+ switch (tc->cmd) {
+ case GETNCNT:
+ case GETZCNT:
+ case GETPID:
+ case GETVAL:
+ case IPC_INFO:
+ tc->func_test(rval);
+ break;
+ default:
+ tc->func_test();
+ break;
+ }
}
-
if (tc->cmd == GETNCNT || tc->cmd == GETZCNT)
kill_all_children();
}
+static void setup(void)
+{
+ sem_id = SAFE_SEMGET(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
+}
+
static void cleanup(void)
{
if (sem_id >= 0)
@@ -305,6 +336,7 @@ static void cleanup(void)
}
static struct tst_test test = {
+ .setup = setup,
.cleanup = cleanup,
.test = verify_semctl,
.tcnt = ARRAY_SIZE(tests),
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [LTP] semctl01: tolerate SEM_STAT races under parallel LTP runs
2026-07-20 22:49 ` [LTP] [PATCH v3] semctl01: tolerate SEM_STAT races under parallel LTP runs Stephen Bertram via ltp
@ 2026-07-20 23:13 ` linuxtestproject.agent
2026-07-20 23:56 ` [LTP] [PATCH v4] " Stephen Bertram via ltp
1 sibling, 0 replies; 8+ messages in thread
From: linuxtestproject.agent @ 2026-07-20 23:13 UTC (permalink / raw)
To: Stephen Bertram; +Cc: ltp
Hi Stephen,
On Mon, 20 Jul 2026 18:49:30 -0400, Stephen Bertram wrote:
> semctl01: tolerate SEM_STAT races under parallel LTP runs
> +static void setup(void)
> +{
> + sem_id = SAFE_SEMGET(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
> +}
Moving the SAFE_SEMGET into setup() breaks multi-iteration runs.
The old code had a lazy-init guard inside verify_semctl():
if (sem_id == -1)
sem_id = SAFE_SEMGET(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
func_rmid() sets sem_id = -1 after IPC_RMID. On the next iteration
verify_semctl(0) calls SAFE_SEMCTL(sem_id=-1, 0, IPC_STAT, ...) which
returns EINVAL and triggers TBROK. Running ./semctl01 -i 2 reproduces
this immediately.
The lazy-init guard (or equivalent per-iteration re-creation) needs to
be kept.
> +static int do_sem_stat(union semun arg)
> +{
> + int idx, rval;
> + unsigned int retries = 5;
> +
> + do {
> + idx = semctl(0, 0, IPC_INFO, (union semun)&ipc_buf);
> + if (idx < 0)
> + tst_brk(TBROK | TERRNO, "semctl(0, 0, IPC_INFO)");
IPC_INFO is a helper call here, not the syscall under test. Can
SAFE_SEMCTL be used instead?
idx = SAFE_SEMCTL(0, 0, IPC_INFO, (union semun)&ipc_buf);
The behaviour is identical; SAFE_SEMCTL already calls tst_brk on
failure.
> + rval = semctl(idx, 0, SEM_STAT, arg);
> + if (rval >= 0) {
> + sem_index = idx;
> + return rval;
> + }
After this patch sem_index has no remaining readers. The *semid field
was removed from struct tcases so the variable is now write-only:
- func_iinfo() writes sem_index = hidx (and sem_index = 0 on TFAIL)
- do_sem_stat() writes sem_index = idx
But nothing reads it. Can sem_index and all three assignment sites be
removed?
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread* [LTP] [PATCH v4] semctl01: tolerate SEM_STAT races under parallel LTP runs
2026-07-20 22:49 ` [LTP] [PATCH v3] semctl01: tolerate SEM_STAT races under parallel LTP runs Stephen Bertram via ltp
2026-07-20 23:13 ` [LTP] " linuxtestproject.agent
@ 2026-07-20 23:56 ` Stephen Bertram via ltp
2026-07-21 2:38 ` [LTP] " linuxtestproject.agent
2026-07-21 13:55 ` [LTP] [PATCH v5] " Stephen Bertram via ltp
1 sibling, 2 replies; 8+ messages in thread
From: Stephen Bertram via ltp @ 2026-07-20 23:56 UTC (permalink / raw)
To: ltp; +Cc: Stephen Bertram, fdarocha
When multiple LTP workers run IPC tests concurrently, SEM_STAT can fail
with EIDRM/EINVAL because the index from IPC_INFO can disappear before
SEM_STAT runs. Retry a few times instead of treating that as TBROK.
The test remains single-threaded; shared globals are intentional.
Test: ./kirk -w 4 -f syscalls_32 -p semctl01 -i 1000
Results summary before:
runtime: 997.690s
passed 415980
failed 0
broken 10
skipped 0
warnings 0
Results summary after:
runtime: 998.593s
passed 416000
failed 0
broken 0
skipped 0
warnings 0
Assisted-by: Cursor
Signed-off-by: Stephen Bertram <sbertram@redhat.com>
---
testcases/kernel/syscalls/semctl/semctl01.c | 84 +++++++++++++--------
1 file changed, 54 insertions(+), 30 deletions(-)
diff --git a/testcases/kernel/syscalls/semctl/semctl01.c b/testcases/kernel/syscalls/semctl/semctl01.c
index 5bd675ab6..78b100455 100644
--- a/testcases/kernel/syscalls/semctl/semctl01.c
+++ b/testcases/kernel/syscalls/semctl/semctl01.c
@@ -19,7 +19,6 @@
#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];
@@ -211,10 +210,8 @@ static void func_rmid(void)
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");
}
}
@@ -236,28 +233,51 @@ static void func_sstat(int semidx)
}
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},
+ {0, IPC_STAT, func_stat, SEMUN_CAST & buf, NULL},
+ {0, IPC_SET, func_set, SEMUN_CAST & buf, set_setup},
+ {0, GETALL, func_gall, SEMUN_CAST array, NULL},
+ {4, GETNCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {2, GETPID, func_pid, SEMUN_CAST & buf, pid_setup},
+ {2, GETVAL, func_gval, SEMUN_CAST & buf, NULL},
+ {4, GETZCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {0, SETALL, func_sall, SEMUN_CAST array, sall_setup},
+ {4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL},
+ {0, IPC_INFO, func_iinfo, SEMUN_CAST & ipc_buf, NULL},
+ {0, SEM_INFO, func_sinfo, SEMUN_CAST & ipc_buf, NULL},
+ {0, SEM_STAT, func_sstat, SEMUN_CAST & buf, NULL},
+ {0, IPC_RMID, func_rmid, SEMUN_CAST & buf, NULL},
};
+/*
+ * SEM_STAT takes an ipc idr index. Under parallel IPC tests that index can
+ * vanish between IPC_INFO and SEM_STAT (EIDRM/EINVAL). Refresh and retry.
+ */
+static int do_sem_stat(union semun arg)
+{
+ int idx, rval;
+ unsigned int retries = 5;
+
+ do {
+ int info_id = 0;
+
+ idx = SAFE_SEMCTL(info_id, 0, IPC_INFO, (union semun)&ipc_buf);
+ rval = semctl(idx, 0, SEM_STAT, arg);
+ if (rval >= 0)
+ return rval;
+ if (errno != EIDRM && errno != EINVAL)
+ tst_brk(TBROK | TERRNO, "semctl(SEM_STAT)");
+ } while (--retries);
+
+ tst_brk(TBROK | TERRNO, "semctl(SEM_STAT) still failing after retries");
+ return -1;
+}
+
static void verify_semctl(unsigned int n)
{
struct tcases *tc = &tests[n];
@@ -265,6 +285,7 @@ static void verify_semctl(unsigned int n)
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:
@@ -279,21 +300,24 @@ static void verify_semctl(unsigned int n)
}
}
- 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:
+ if (tc->cmd == SEM_STAT) {
+ rval = do_sem_stat(tc->arg);
tc->func_test(rval);
- break;
- default:
- tc->func_test();
- break;
+ } else {
+ rval = SAFE_SEMCTL(sem_id, tc->semnum, tc->cmd, tc->arg);
+ switch (tc->cmd) {
+ case GETNCNT:
+ case GETZCNT:
+ case GETPID:
+ case GETVAL:
+ case IPC_INFO:
+ tc->func_test(rval);
+ break;
+ default:
+ tc->func_test();
+ break;
+ }
}
-
if (tc->cmd == GETNCNT || tc->cmd == GETZCNT)
kill_all_children();
}
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [LTP] semctl01: tolerate SEM_STAT races under parallel LTP runs
2026-07-20 23:56 ` [LTP] [PATCH v4] " Stephen Bertram via ltp
@ 2026-07-21 2:38 ` linuxtestproject.agent
2026-07-21 13:55 ` [LTP] [PATCH v5] " Stephen Bertram via ltp
1 sibling, 0 replies; 8+ messages in thread
From: linuxtestproject.agent @ 2026-07-21 2:38 UTC (permalink / raw)
To: Stephen Bertram; +Cc: ltp
Hi Stephen,
On Mon Jul 20 19:56:47 2026, Stephen Bertram wrote:
> semctl01: tolerate SEM_STAT races under parallel LTP runs
> +static int do_sem_stat(union semun arg)
> +{
> + int idx, rval;
> + unsigned int retries = 5;
> +
> + do {
> + int info_id = 0;
> +
> + idx = SAFE_SEMCTL(info_id, 0, IPC_INFO, (union semun)&ipc_buf);
> + rval = semctl(idx, 0, SEM_STAT, arg);
> + if (rval >= 0)
> + return rval;
> + if (errno != EIDRM && errno != EINVAL)
> + tst_brk(TBROK | TERRNO, "semctl(SEM_STAT)");
> + } while (--retries);
semctl() is the subject syscall of this test. The rule for subject
syscalls is: skip SAFE_* (done correctly), but wrap the call in TEST()
or a TST_EXP_* macro -- never call it bare. Something like:
TEST(semctl(idx, 0, SEM_STAT, arg));
if (TST_RET >= 0)
return TST_RET;
if (TST_ERR != EIDRM && TST_ERR != EINVAL)
tst_brk(TBROK | TERRNO, "semctl(SEM_STAT)");
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread* [LTP] [PATCH v5] semctl01: tolerate SEM_STAT races under parallel LTP runs
2026-07-20 23:56 ` [LTP] [PATCH v4] " Stephen Bertram via ltp
2026-07-21 2:38 ` [LTP] " linuxtestproject.agent
@ 2026-07-21 13:55 ` Stephen Bertram via ltp
2026-07-21 14:40 ` [LTP] " linuxtestproject.agent
1 sibling, 1 reply; 8+ messages in thread
From: Stephen Bertram via ltp @ 2026-07-21 13:55 UTC (permalink / raw)
To: ltp; +Cc: Stephen Bertram, fdarocha
When multiple LTP workers run IPC tests concurrently, SEM_STAT can fail
with EIDRM/EINVAL because the index from IPC_INFO can disappear before
SEM_STAT runs. Retry a few times instead of treating that as TBROK.
The test remains single-threaded; shared globals are intentional.
Test: ./kirk -w 4 -f syscalls_32 -p semctl01 -i 1000
Results summary before:
runtime: 997.690s
passed 415980
failed 0
broken 10
skipped 0
warnings 0
Results summary after:
runtime: 998.593s
passed 416000
failed 0
broken 0
skipped 0
warnings 0
Assisted-by: Cursor
Signed-off-by: Stephen Bertram <sbertram@redhat.com>
---
testcases/kernel/syscalls/semctl/semctl01.c | 84 +++++++++++++--------
1 file changed, 54 insertions(+), 30 deletions(-)
diff --git a/testcases/kernel/syscalls/semctl/semctl01.c b/testcases/kernel/syscalls/semctl/semctl01.c
index 5bd675ab6..c0e9e8f41 100644
--- a/testcases/kernel/syscalls/semctl/semctl01.c
+++ b/testcases/kernel/syscalls/semctl/semctl01.c
@@ -19,7 +19,6 @@
#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];
@@ -211,10 +210,8 @@ static void func_rmid(void)
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");
}
}
@@ -236,28 +233,51 @@ static void func_sstat(int semidx)
}
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},
+ {0, IPC_STAT, func_stat, SEMUN_CAST & buf, NULL},
+ {0, IPC_SET, func_set, SEMUN_CAST & buf, set_setup},
+ {0, GETALL, func_gall, SEMUN_CAST array, NULL},
+ {4, GETNCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {2, GETPID, func_pid, SEMUN_CAST & buf, pid_setup},
+ {2, GETVAL, func_gval, SEMUN_CAST & buf, NULL},
+ {4, GETZCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
+ {0, SETALL, func_sall, SEMUN_CAST array, sall_setup},
+ {4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL},
+ {0, IPC_INFO, func_iinfo, SEMUN_CAST & ipc_buf, NULL},
+ {0, SEM_INFO, func_sinfo, SEMUN_CAST & ipc_buf, NULL},
+ {0, SEM_STAT, func_sstat, SEMUN_CAST & buf, NULL},
+ {0, IPC_RMID, func_rmid, SEMUN_CAST & buf, NULL},
};
+/*
+ * SEM_STAT takes an ipc idr index. Under parallel IPC tests that index can
+ * vanish between IPC_INFO and SEM_STAT (EIDRM/EINVAL). Refresh and retry.
+ */
+static int do_sem_stat(union semun arg)
+{
+ int idx;
+ unsigned int retries = 5;
+
+ do {
+ int info_id = 0;
+
+ idx = SAFE_SEMCTL(info_id, 0, IPC_INFO, (union semun)&ipc_buf);
+ TEST(semctl(idx, 0, SEM_STAT, arg));
+ if (TST_RET >= 0)
+ return TST_RET;
+ if (TST_ERR != EIDRM && TST_ERR != EINVAL)
+ tst_brk(TBROK | TERRNO, "semctl(SEM_STAT)");
+ } while (--retries);
+
+ tst_brk(TBROK | TERRNO, "semctl(SEM_STAT) still failing after retries");
+ return -1;
+}
+
static void verify_semctl(unsigned int n)
{
struct tcases *tc = &tests[n];
@@ -265,6 +285,7 @@ static void verify_semctl(unsigned int n)
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:
@@ -279,21 +300,24 @@ static void verify_semctl(unsigned int n)
}
}
- 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:
+ if (tc->cmd == SEM_STAT) {
+ rval = do_sem_stat(tc->arg);
tc->func_test(rval);
- break;
- default:
- tc->func_test();
- break;
+ } else {
+ rval = SAFE_SEMCTL(sem_id, tc->semnum, tc->cmd, tc->arg);
+ switch (tc->cmd) {
+ case GETNCNT:
+ case GETZCNT:
+ case GETPID:
+ case GETVAL:
+ case IPC_INFO:
+ tc->func_test(rval);
+ break;
+ default:
+ tc->func_test();
+ break;
+ }
}
-
if (tc->cmd == GETNCNT || tc->cmd == GETZCNT)
kill_all_children();
}
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-07-21 14:40 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-14 16:49 [LTP] [PATCH v2] semctl: updates for multi worker testing Stephen Bertram via ltp
2026-04-14 17:15 ` [LTP] " linuxtestproject.agent
2026-07-20 22:49 ` [LTP] [PATCH v3] semctl01: tolerate SEM_STAT races under parallel LTP runs Stephen Bertram via ltp
2026-07-20 23:13 ` [LTP] " linuxtestproject.agent
2026-07-20 23:56 ` [LTP] [PATCH v4] " Stephen Bertram via ltp
2026-07-21 2:38 ` [LTP] " linuxtestproject.agent
2026-07-21 13:55 ` [LTP] [PATCH v5] " Stephen Bertram via ltp
2026-07-21 14:40 ` [LTP] " linuxtestproject.agent
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.