i386: Disable Intel Xeon Phi tests for GCC 15 and above (BZ 31782)
[glibc.git] / sysdeps / unix / sysv / linux / tst-sysvshm-linux.c
blob5f2082b3b4810a520f8146c39cd46c6bee3b2277
1 /* Basic tests for Linux SYSV shared memory extensions.
2 Copyright (C) 2020-2024 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/shm.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <inttypes.h>
27 #include <limits.h>
29 #include <support/check.h>
30 #include <support/temp_file.h>
32 #define SHM_MODE 0644
34 /* These are for the temporary file we generate. */
35 static char *name;
36 static int shmid;
37 static long int pgsz;
39 static void
40 remove_shm (void)
42 /* Enforce message queue removal in case of early test failure.
43 Ignore error since the shm may already have being removed. */
44 shmctl (shmid, IPC_RMID, NULL);
47 static void
48 do_prepare (int argc, char *argv[])
50 TEST_VERIFY_EXIT (create_temp_file ("tst-sysvshm.", &name) != -1);
53 #define PREPARE do_prepare
55 struct test_shminfo
57 __syscall_ulong_t shmall;
58 __syscall_ulong_t shmmax;
59 __syscall_ulong_t shmmni;
62 /* It tries to obtain some system-wide SysV shared memory information from
63 /proc to check against IPC_INFO/SHM_INFO. The /proc only returns the
64 tunables value of SHMALL, SHMMAX, and SHMMNI. */
66 static uint64_t
67 read_proc_file (const char *file)
69 FILE *f = fopen (file, "r");
70 if (f == NULL)
71 FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file);
73 /* Handle 32-bit binaries running on 64-bit kernels. */
74 uint64_t v;
75 int r = fscanf (f, "%" SCNu64, &v);
76 TEST_VERIFY_EXIT (r == 1);
78 fclose (f);
79 return v;
83 /* Check if the message queue with IDX (index into the kernel's internal
84 array) matches the one with KEY. The CMD is either SHM_STAT or
85 SHM_STAT_ANY. */
87 static bool
88 check_shminfo (int idx, key_t key, int cmd)
90 struct shmid_ds shminfo;
91 int sid = shmctl (idx, cmd, &shminfo);
92 /* Ignore unused array slot returned by the kernel or information from
93 unknown message queue. */
94 if ((sid == -1 && errno == EINVAL) || sid != shmid)
95 return false;
97 if (sid == -1)
98 FAIL_EXIT1 ("shmctl with %s failed: %m",
99 cmd == SHM_STAT ? "SHM_STAT" : "SHM_STAT_ANY");
101 TEST_COMPARE (shminfo.shm_perm.__key, key);
102 TEST_COMPARE (shminfo.shm_perm.mode, SHM_MODE);
103 TEST_COMPARE (shminfo.shm_segsz, pgsz);
105 return true;
108 static int
109 do_test (void)
111 atexit (remove_shm);
113 pgsz = sysconf (_SC_PAGESIZE);
114 if (pgsz == -1)
115 FAIL_EXIT1 ("sysconf (_SC_PAGESIZE) failed: %m");
117 key_t key = ftok (name, 'G');
118 if (key == -1)
119 FAIL_EXIT1 ("ftok failed: %m");
121 shmid = shmget (key, pgsz, IPC_CREAT | IPC_EXCL | SHM_MODE);
122 if (shmid == -1)
123 FAIL_EXIT1 ("shmget failed: %m");
125 /* It does not check shmmax because kernel clamp its value to INT_MAX for:
127 1. Compat symbols with IPC_64, i.e, 32-bit binaries running on 64-bit
128 kernels.
130 2. Default symbol without IPC_64 (defined as IPC_OLD within Linux) and
131 glibc always use IPC_64 for 32-bit ABIs (to support 64-bit time_t).
132 It means that 32-bit binaries running on 32-bit kernels will not see
133 shmmax being clamped.
135 And finding out whether the compat symbol is used would require checking
136 the underlying kernel against the current ABI. The shmall and shmmni
137 already provided enough coverage. */
139 struct test_shminfo tipcinfo;
140 tipcinfo.shmall = read_proc_file ("/proc/sys/kernel/shmall");
141 tipcinfo.shmmni = read_proc_file ("/proc/sys/kernel/shmmni");
143 int shmidx;
145 /* Note: SHM_INFO does not return a shminfo, but rather a 'struct shm_info'.
146 It is tricky to verify its values since the syscall returns system wide
147 resources consumed by shared memory. The shmctl implementation handles
148 SHM_INFO as IPC_INFO, so the IPC_INFO test should validate SHM_INFO as
149 well. */
152 struct shminfo ipcinfo;
153 shmidx = shmctl (shmid, IPC_INFO, (struct shmid_ds *) &ipcinfo);
154 if (shmidx == -1)
155 FAIL_EXIT1 ("shmctl with IPC_INFO failed: %m");
157 TEST_COMPARE (ipcinfo.shmall, tipcinfo.shmall);
158 TEST_COMPARE (ipcinfo.shmmni, tipcinfo.shmmni);
161 /* We check if the created shared memory shows in the global list. */
162 bool found = false;
163 for (int i = 0; i <= shmidx; i++)
165 /* We can't tell apart if SHM_STAT_ANY is not supported (kernel older
166 than 4.17) or if the index used is invalid. So it just check if
167 value returned from a valid call matches the created message
168 queue. */
169 check_shminfo (i, key, SHM_STAT_ANY);
171 if (check_shminfo (i, key, SHM_STAT))
173 found = true;
174 break;
178 if (!found)
179 FAIL_EXIT1 ("shmctl with SHM_STAT/SHM_STAT_ANY could not find the "
180 "created shared memory");
182 if (shmctl (shmid, IPC_RMID, NULL) == -1)
183 FAIL_EXIT1 ("shmctl failed");
185 return 0;
188 #include <support/test-driver.c>