Skip to content

Commit 68f883b

Browse files
authored
Merge pull request #1535 from LinuxCNC/hal-init-race
fix hal_init() race
2 parents cd22b5e + 29b4890 commit 68f883b

8 files changed

Lines changed: 157 additions & 18 deletions

File tree

docs/man/man3/rtapi_shmem.3rtapi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ wishing to access the same memory must use the same key.
3535
\fImodule_id\fR is the ID of the module that is making the call (see
3636
rtapi_init). The block will be at least \fIsize\fR bytes, and may
3737
be rounded up. Allocating many small blocks may be very wasteful.
38-
When a particular block is allocated for the first time, the first
39-
4 bytes are zeroed. Subsequent allocations of the same block
38+
When a particular block is allocated for the first time, the contents
39+
are zeroed. Subsequent allocations of the same block
4040
by other modules or processes will not touch the contents of the
4141
block. Applications can use those bytes to see if they need to
4242
initialize the block, or if another module already did so.

src/hal/hal_lib.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ int hal_exit(int comp_id)
349349
--ref_cnt;
350350
#ifdef ULAPI
351351
if(ref_cnt == 0) {
352-
rtapi_print_msg(RTAPI_MSG_DBG, "HAL: releasing RTAPI resources");
352+
rtapi_print_msg(RTAPI_MSG_DBG, "HAL: releasing RTAPI resources\n");
353353
/* release RTAPI resources */
354354
rtapi_shmem_delete(lib_mem_id, lib_module_id);
355355
rtapi_exit(lib_module_id);
@@ -2781,19 +2781,29 @@ static void thread_task(void *arg)
27812781

27822782
static int init_hal_data(void)
27832783
{
2784-
/* has the block already been initialized? */
2784+
/* has the hal_data block already been initialized? */
2785+
2786+
/* Lock hal_data by taking the mutex, so that two processes
2787+
don't both try to initialize hal_data at the same time. NOTE:
2788+
The first time through, the hal_data memory buffer is fresh from
2789+
rtapi_shmem_new(), which means it's initialized to all zero bytes.
2790+
This means hal_data->mutex is valid and unlocked. */
2791+
rtapi_mutex_get(&(hal_data->mutex));
2792+
27852793
if (hal_data->version != 0) {
2786-
/* yes, verify version code */
2787-
if (hal_data->version == HAL_VER) {
2788-
return 0;
2789-
} else {
2790-
rtapi_print_msg(RTAPI_MSG_ERR,
2791-
"HAL: ERROR: version code mismatch\n");
2792-
return -1;
2793-
}
2794+
/* hal_data has been initialized already, verify version code */
2795+
if (hal_data->version == HAL_VER) {
2796+
rtapi_mutex_give(&(hal_data->mutex));
2797+
return 0;
2798+
} else {
2799+
rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: version code mismatch\n");
2800+
rtapi_mutex_give(&(hal_data->mutex));
2801+
return -1;
2802+
}
27942803
}
2795-
/* no, we need to init it, grab the mutex unconditionally */
2796-
rtapi_mutex_try(&(hal_data->mutex));
2804+
2805+
/* hal_data has *NOT* been initialized yet, we get the honor */
2806+
27972807
/* set version code so nobody else init's the block */
27982808
hal_data->version = HAL_VER;
27992809
/* initialize everything */

src/rtapi/rtapi.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,10 @@ RTAPI_BEGIN_DECLS
431431
'module_id' is the ID of the module that is making the call (see
432432
rtapi_init). The block will be at least 'size' bytes, and may
433433
be rounded up. Allocating many small blocks may be very wasteful.
434-
When a particular block is allocated for the first time, the first
435-
4 bytes are zeroed. Subsequent allocations of the same block
434+
When a particular block is allocated for the first time, all
435+
bytes are zeroed. Subsequent allocations of the same block
436436
by other modules or processes will not touch the contents of the
437-
block. Applications can use those bytes to see if they need to
438-
initialize the block, or if another module already did so.
437+
block.
439438
On success, it returns a positive integer ID, which is used for
440439
all subsequent calls dealing with the block. On failure it
441440
returns a negative error code. Call only from within user or

tests/rtapi-shmem/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This test allocates some shared memory from RTAPI, and verifies that it
2+
is initialized to all bytes zero.

tests/rtapi-shmem/checkresult

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
exit 0

tests/rtapi-shmem/setup.hal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
debug 5
2+
loadrt test_shmem_rtcomp

tests/rtapi-shmem/test.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
3+
halcompile --install test_shmem_rtcomp.comp
4+
5+
halrun -V setup.hal
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2022 Sebastian Kuzminsky <seb@highlab.com>
2+
//
3+
// This program is free software; you can redistribute it and/or
4+
// modify it under the terms of version 2 of the GNU General
5+
// Public License as published by the Free Software Foundation.
6+
//
7+
// This program is distributed in the hope that it will be useful,
8+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
// GNU General Public License for more details.
11+
//
12+
// You should have received a copy of the GNU General Public License
13+
// along with this program; if not, write to the Free Software
14+
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15+
16+
component test_shmem_rtcomp "Validate rtapi's shmem initialization behavior";
17+
18+
option extra_setup;
19+
option extra_cleanup;
20+
option singleton;
21+
22+
pin out bit ready = 0 "Goes true when shmem is initialized";
23+
24+
function _;
25+
license "GPL";
26+
27+
;;
28+
29+
#include <rtapi.h>
30+
31+
#define SHMEM_KEY 9999
32+
#define SHMEM_SIZE (4096 * 100) // in bytes
33+
34+
int shmem_id = -1;
35+
void *mem = NULL;
36+
37+
int shmem_alloc(void) {
38+
int i;
39+
int r;
40+
uint8_t *p;
41+
42+
rtapi_print_msg(RTAPI_MSG_ERR, "allocating shmem\n");
43+
44+
shmem_id = rtapi_shmem_new(SHMEM_KEY, comp_id, SHMEM_SIZE);
45+
if (shmem_id < 0) {
46+
rtapi_print_msg(RTAPI_MSG_ERR, "failed to make new rtapi shmem\n");
47+
return -EINVAL;
48+
}
49+
50+
r = rtapi_shmem_getptr(shmem_id, &mem);
51+
if (r < 0) {
52+
rtapi_print_msg(RTAPI_MSG_ERR, "failed to get new rtapi shmem\n");
53+
return -EINVAL;
54+
}
55+
if (mem == NULL) {
56+
rtapi_print_msg(RTAPI_MSG_ERR, "new rtapi shmem is NULL??\n");
57+
return -EINVAL;
58+
}
59+
60+
p = mem;
61+
for (i = 0; i < SHMEM_SIZE; ++i) {
62+
if (p[i] != 0x00) {
63+
rtapi_print_msg(RTAPI_MSG_ERR, "shmem is not initialized to 0x00!\n");
64+
return -EINVAL;
65+
}
66+
}
67+
68+
rtapi_print_msg(RTAPI_MSG_ERR, "allocated shmem came initialized to all bytes zero\n");
69+
70+
return 0;
71+
}
72+
73+
74+
void shmem_free(void) {
75+
if (shmem_id >= 0) {
76+
rtapi_print_msg(RTAPI_MSG_ERR, "freeing shmem\n");
77+
rtapi_shmem_delete(shmem_id, comp_id);
78+
}
79+
}
80+
81+
82+
EXTRA_SETUP() {
83+
int i;
84+
int r;
85+
uint8_t *p;
86+
87+
r = shmem_alloc();
88+
if (r < 0) {
89+
rtapi_print_msg(RTAPI_MSG_ERR, "failed to alloc shmem\n");
90+
return -EINVAL;
91+
}
92+
93+
// dirty the shmem
94+
p = mem;
95+
for (i = 0; i < SHMEM_SIZE; ++i) {
96+
p[i] = i % 256;
97+
}
98+
99+
shmem_free();
100+
101+
r = shmem_alloc();
102+
if (r < 0) {
103+
rtapi_print_msg(RTAPI_MSG_ERR, "failed to alloc shmem\n");
104+
return -EINVAL;
105+
}
106+
107+
return 0;
108+
}
109+
110+
111+
EXTRA_CLEANUP() {
112+
shmem_free();
113+
}
114+
115+
116+
FUNCTION(_) {
117+
ready = 1;
118+
}
119+

0 commit comments

Comments
 (0)