Reputation: 175
I have a multithreaded linux app written in c running on a i.mx6 arm. I have a 25lc256 spi eeprom mapped to the file system. Writes are relatively slow at the driver level, not much can be done there. The problem is that file functions are blocking other threads for too long. usleep additions don't seem to help, it appears I'll have to do something different, but its not clear to me what to change.
The output on this calling this function from one thread is
EEprom write
EEprom saved in 522.000000 703.000000 705.000000 723.000000 662596.000000 1328858.000000
Capture -EPIPE snd_pcm_prepare
With Capture -EPIPE snd_pcm_prepare coming from the thread where the audio buffer underran because of the blocked thread, I suppose.
int SaveCurrentConfig(void) {//EEPROM
int r = 1;
struct timeval tvs, tv1, tv2, tv3, tv4, tv5, tv6;
gettimeofday(&tvs, NULL);
printf("EEprom write\n");
pthread_mutex_lock(&eepromconfigmutex);
{
char * ConfigXml = BuildXmlConfig();
FILE * WriteConfig = fopen(ConfigPath, "w");
if (WriteConfig == NULL) {
MyLog("Unable to open eeprom %s\n", strerror(errno));
r = 0;
goto badfinish;
}
gettimeofday(&tv1, NULL);
size_t len = strlen(ConfigXml);
unsigned short CRC = ComputeChecksum(ConfigXml, len);
fwrite((char*) &len, 1, sizeof (size_t), WriteConfig);
gettimeofday(&tv2, NULL);
fwrite((char*) &CRC, 1, 2, WriteConfig);
gettimeofday(&tv3, NULL);
fwrite(ConfigXml, 1, strlen(ConfigXml), WriteConfig);
gettimeofday(&tv4, NULL);
fseek(WriteConfig, ConfigOffset2, SEEK_SET);
fwrite((char*) &len, 1, sizeof (size_t), WriteConfig);
fwrite((char*) &CRC, 1, 2, WriteConfig);
fwrite(ConfigXml, 1, strlen(ConfigXml), WriteConfig);
gettimeofday(&tv5, NULL);
fclose(WriteConfig);
badfinish:
free(ConfigXml);
}
pthread_mutex_unlock(&eepromconfigmutex);
gettimeofday(&tv6, NULL);
double diff1 = time_diff(tvs, tv1);
double diff2 = time_diff(tvs, tv2);
double diff3 = time_diff(tvs, tv3);
double diff4 = time_diff(tvs, tv4);
double diff5 = time_diff(tvs, tv5);
double diff6 = time_diff(tvs, tv6);
printf("EEprom saved in %f %f %f %f %f %f\n", diff1, diff2, diff3, diff4, diff5, diff6);
return r;
}
Upvotes: 1
Views: 1133
Reputation: 239311
If that thread calling fclose()
is blocking other threads from running for long periods, then the problem is likely that it is spending a lot of time in kernel mode inside the eeprom driver code, flushing out the pending writes.
There's a few things you could try:
PREEMPT
configuration option selected. This will allow the thread to be preempted while it's running the eeprom driver code.fflush()
after writing a smaller block of data (you may need to also call fsync()
on the underlying file descriptor).Upvotes: 1
Reputation: 995
I would try an
fflush( WriteConfig );
just before your
fclose(WriteConfig);
Upvotes: 0
Reputation: 2685
Looks like the problem is in fclose()
. fclose()
, but default, will not return until the contents of the file have been written to disk. I believe you can force it to return early with O_NONBLOCK
, from man 2 open
:
O_NONBLOCK or O_NDELAY
When possible, the file is opened in nonblocking mode. Neither the open() nor any subsequent operations on the file descriptor which is returned will cause the calling process to wait. For the handling of FIFOs (named pipes), see also fifo(7). For a discus‐ sion of the effect of O_NONBLOCK in conjunction with mandatory file locks and with file leases, see fcntl(2).
You can try this out with:
int fd = open(ConfigPath, O_WRONLY | O_NONBLOCK);
FILE * WriteConfig = fdopen(fd, "w");
Upvotes: 0