I have a single board computer with a I2C GPIO expander device, listed as /dev/i2c-0. In my multithreaded program I open() this character device and read/write to it on separate threads using i2c_smbus_write_byte_data and friends from the libi2c library, but I am not sure if that is thread-safe.
I have seen kernel space GPIO driver implementations that bind over the I2C character device and allow to interface with the device as if it was a GPIO device (pca953x driver) and they have internal mutexes within every gpio_set/get function. In another question people say i2c_smbus_* functions have internal mutexes so I cannot be sure.
Is this kind of concurrent access thread-safe?
void *thread_fn(void *arg){
int fd = *(int*)arg;
uint16_t d;
for(uint16_t i=0;i<1000;i++) {
if (i%2==0){
d = i2c_smbus_read_word_data(fd, REG);
} else {
d |= 1 << (i%16);
i2c_smbus_write_word_data(fd, REG, d);
}
}
return NULL;
}
int main(void){
int fd = open("/dev/i2c-0");
pthread_t t;
pthread_create(&t, NULL, thread_fn, &fd);
for(uint16_t i=0;i<1000;i++)
i2c_smbus_write_word_data(fd, REG, i);
pthread_join(t, NULL);
return 0;
}
-
1Why don’t you use the kernel driver for that expander which is definitely thread-safe?0andriy– 0andriy2025年10月20日 10:33:09 +00:00Commented Oct 20 at 10:33
-
@0andriy On the IO, I need a precise square wave output at high frequencies up to 8kHz. That is not feasible with the gpio driver (I measured with an oscilloscope) and I assume the reason is the constant locking/unlocking. On the contrary, when I interface with it as a I2C device, I can go up to high frequencies even with a userspace mutex and careful scheduling of the IO access. That's what made me think that maybe the mutex in the driver is redundant.j-hc– j-hc2025年10月20日 11:36:08 +00:00Commented Oct 20 at 11:36
-
1No, the problem is the choosen (SW) tool. Linux kernel is General Purpose multi-tasking OS, doing what you want requires quite a high priority task to guarantee the desired latency. You may consider PREEMPT_RT kernel, but still the application needs to be properly written for that. What you have working is just by luck (mostly idling system, with likely a single user which also does nothing). That said, using in-kernel driver is a good start (and user space driver for I²C component like that in GP OS is quite controversial move).0andriy– 0andriy2025年10月20日 18:09:31 +00:00Commented Oct 20 at 18:09