Update copyright dates with scripts/update-copyrights
[glibc.git] / sysdeps / unix / sysv / linux / tst-sysvsem-linux.c
blob3d7b834987aafd88a9ba2035f393fd07adac54e5
1 /* Basic tests for Linux SYSV semaphore extensions.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <sys/ipc.h>
20 #include <sys/sem.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <stdio.h>
26 #include <support/check.h>
27 #include <support/temp_file.h>
29 /* These are for the temporary file we generate. */
30 static char *name;
31 static int semid;
33 static void
34 remove_sem (void)
36 /* Enforce message queue removal in case of early test failure.
37 Ignore error since the sem may already have being removed. */
38 semctl (semid, 0, IPC_RMID, 0);
41 static void
42 do_prepare (int argc, char *argv[])
44 TEST_VERIFY_EXIT (create_temp_file ("tst-sysvsem.", &name) != -1);
47 #define PREPARE do_prepare
49 #define SEM_MODE 0644
51 union semun
53 int val;
54 struct semid_ds *buf;
55 unsigned short *array;
56 struct seminfo *__buf;
59 struct test_seminfo
61 int semmsl;
62 int semmns;
63 int semopm;
64 int semmni;
67 /* It tries to obtain some system-wide SysV semaphore information from /proc
68 to check against IPC_INFO/SEM_INFO. The /proc only returns the tunables
69 value of SEMMSL, SEMMNS, SEMOPM, and SEMMNI.
71 The kernel also returns constant value for SEMVMX, SEMMNU, SEMMAP, SEMUME,
72 and also SEMUSZ and SEMAEM (for IPC_INFO). The issue to check them is they
73 might change over kernel releases. */
75 static void
76 read_sem_stat (struct test_seminfo *tseminfo)
78 FILE *f = fopen ("/proc/sys/kernel/sem", "r");
79 if (f == NULL)
80 FAIL_UNSUPPORTED ("/proc is not mounted or /proc/sys/kernel/sem is not "
81 "available");
83 int r = fscanf (f, "%d %d %d %d",
84 &tseminfo->semmsl, &tseminfo->semmns, &tseminfo->semopm,
85 &tseminfo->semmni);
86 TEST_VERIFY_EXIT (r == 4);
88 fclose (f);
92 /* Check if the semaphore with IDX (index into the kernel's internal array)
93 matches the one with KEY. The CMD is either SEM_STAT or SEM_STAT_ANY. */
95 static bool
96 check_seminfo (int idx, key_t key, int cmd)
98 struct semid_ds seminfo;
99 int sid = semctl (idx, 0, cmd, (union semun) { .buf = &seminfo });
100 /* Ignore unused array slot returned by the kernel or information from
101 unknown semaphores. */
102 if ((sid == -1 && errno == EINVAL) || sid != semid)
103 return false;
105 if (sid == -1)
106 FAIL_EXIT1 ("semctl with SEM_STAT failed (errno=%d)", errno);
108 TEST_COMPARE (seminfo.sem_perm.__key, key);
109 TEST_COMPARE (seminfo.sem_perm.mode, SEM_MODE);
110 TEST_COMPARE (seminfo.sem_nsems, 1);
112 return true;
115 static int
116 do_test (void)
118 atexit (remove_sem);
120 key_t key = ftok (name, 'G');
121 if (key == -1)
122 FAIL_EXIT1 ("ftok failed: %m");
124 semid = semget (key, 1, IPC_CREAT | IPC_EXCL | SEM_MODE);
125 if (semid == -1)
126 FAIL_EXIT1 ("semget failed: %m");
128 struct test_seminfo tipcinfo;
129 read_sem_stat (&tipcinfo);
131 int semidx;
134 struct seminfo ipcinfo;
135 semidx = semctl (semid, 0, IPC_INFO, (union semun) { .__buf = &ipcinfo });
136 if (semidx == -1)
137 FAIL_EXIT1 ("semctl with IPC_INFO failed: %m");
139 TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl);
140 TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns);
141 TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm);
142 TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni);
145 /* Same as before but with SEM_INFO. */
147 struct seminfo ipcinfo;
148 semidx = semctl (semid, 0, SEM_INFO, (union semun) { .__buf = &ipcinfo });
149 if (semidx == -1)
150 FAIL_EXIT1 ("semctl with IPC_INFO failed: %m");
152 TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl);
153 TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns);
154 TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm);
155 TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni);
158 /* We check if the created semaphore shows in the system-wide status. */
159 bool found = false;
160 for (int i = 0; i <= semidx; i++)
162 /* We can't tell apart if SEM_STAT_ANY is not supported (kernel older
163 than 4.17) or if the index used is invalid. So it just check if
164 value returned from a valid call matches the created semaphore. */
165 check_seminfo (i, key, SEM_STAT_ANY);
167 if (check_seminfo (i, key, SEM_STAT))
169 found = true;
170 break;
174 if (!found)
175 FAIL_EXIT1 ("semctl with SEM_STAT/SEM_STAT_ANY could not find the "
176 "created semaphore");
178 if (semctl (semid, 0, IPC_RMID, 0) == -1)
179 FAIL_EXIT1 ("semctl failed: %m");
181 return 0;
184 #include <support/test-driver.c>