Is it possible to interrupt the copy process of a struct by an interrupt in embedded C?
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
6
down vote
favorite
Inside the driver I have got a function to copy the data from the internal struct into a struct from the application.
Can this process be interrupted by a microcontroller interrupt trigger?
uint16_t getRawData(struct Data *Data_external)
if(Data_external == NULL)
return ERR_PARA;
else
*Data_external = Data_internal; // the copy process. Could this be interrupted?
return ERR_NONE;
microcontroller c embedded interrupts
 |Â
show 8 more comments
up vote
6
down vote
favorite
Inside the driver I have got a function to copy the data from the internal struct into a struct from the application.
Can this process be interrupted by a microcontroller interrupt trigger?
uint16_t getRawData(struct Data *Data_external)
if(Data_external == NULL)
return ERR_PARA;
else
*Data_external = Data_internal; // the copy process. Could this be interrupted?
return ERR_NONE;
microcontroller c embedded interrupts
17
There isn't really a "copy process", there will be instructions copying bytes around and if they are not atomic they can be interrupted, depends on your architecture, compiler, settings and alignment
â PlasmaHH
Sep 6 at 9:28
10
There is no guarantee in C that a structure copying process cannot be interrupted. However, the interrupt is usually supposed to return to the point in the code where the copying process can complete. So it probably doesn't matter unless the interrupt code depends upon it for some reason (unlikely in most circumstances.) If these structures are part of a upper/lower interrupt driver pair, though, then this could be a problem if the upper level is in the process of removing or adding a "chunk" to a buffer when an interrupt takes place that must also cope with "chunks" in the same buffer.
â jonk
Sep 6 at 9:35
4
@jonk: Please do not answer the question in comments, as this bypasses the normal review process for answers, as discussed in meta
â Dave Tweedâ¦
Sep 6 at 18:50
6
@DaveTweed Then you and this site will lose my comments. I don't write answers unless I have the time to write fuller ones. It's my only way of operation and I won't change it. If I feel I have enough time for a "proper answer" by my definition of it, I will continue as before. But I'm working very hard on several different active projects and do NOT have the time for my usual level of answer context and content. So either I write short comments as comments, or the site loses any access to my time. Your call. My time is given on my terms, or not at all.
â jonk
Sep 6 at 18:57
4
@jonk: There's nothing wrong with writing a short answer as long as it is complete and self-contained, like your comment is. Your commitment to lengthy answers is entirely on you. The site has rules and processes, and I'm just trying to nudge you in the right direction. Ultimately, it's entirely up to you -- you could have had 9 upvotes (+90 rep) on your answer...
â Dave Tweedâ¦
Sep 6 at 20:08
 |Â
show 8 more comments
up vote
6
down vote
favorite
up vote
6
down vote
favorite
Inside the driver I have got a function to copy the data from the internal struct into a struct from the application.
Can this process be interrupted by a microcontroller interrupt trigger?
uint16_t getRawData(struct Data *Data_external)
if(Data_external == NULL)
return ERR_PARA;
else
*Data_external = Data_internal; // the copy process. Could this be interrupted?
return ERR_NONE;
microcontroller c embedded interrupts
Inside the driver I have got a function to copy the data from the internal struct into a struct from the application.
Can this process be interrupted by a microcontroller interrupt trigger?
uint16_t getRawData(struct Data *Data_external)
if(Data_external == NULL)
return ERR_PARA;
else
*Data_external = Data_internal; // the copy process. Could this be interrupted?
return ERR_NONE;
microcontroller c embedded interrupts
edited Sep 6 at 11:35
Michel Keijzers
4,66152149
4,66152149
asked Sep 6 at 9:27
Stani
497
497
17
There isn't really a "copy process", there will be instructions copying bytes around and if they are not atomic they can be interrupted, depends on your architecture, compiler, settings and alignment
â PlasmaHH
Sep 6 at 9:28
10
There is no guarantee in C that a structure copying process cannot be interrupted. However, the interrupt is usually supposed to return to the point in the code where the copying process can complete. So it probably doesn't matter unless the interrupt code depends upon it for some reason (unlikely in most circumstances.) If these structures are part of a upper/lower interrupt driver pair, though, then this could be a problem if the upper level is in the process of removing or adding a "chunk" to a buffer when an interrupt takes place that must also cope with "chunks" in the same buffer.
â jonk
Sep 6 at 9:35
4
@jonk: Please do not answer the question in comments, as this bypasses the normal review process for answers, as discussed in meta
â Dave Tweedâ¦
Sep 6 at 18:50
6
@DaveTweed Then you and this site will lose my comments. I don't write answers unless I have the time to write fuller ones. It's my only way of operation and I won't change it. If I feel I have enough time for a "proper answer" by my definition of it, I will continue as before. But I'm working very hard on several different active projects and do NOT have the time for my usual level of answer context and content. So either I write short comments as comments, or the site loses any access to my time. Your call. My time is given on my terms, or not at all.
â jonk
Sep 6 at 18:57
4
@jonk: There's nothing wrong with writing a short answer as long as it is complete and self-contained, like your comment is. Your commitment to lengthy answers is entirely on you. The site has rules and processes, and I'm just trying to nudge you in the right direction. Ultimately, it's entirely up to you -- you could have had 9 upvotes (+90 rep) on your answer...
â Dave Tweedâ¦
Sep 6 at 20:08
 |Â
show 8 more comments
17
There isn't really a "copy process", there will be instructions copying bytes around and if they are not atomic they can be interrupted, depends on your architecture, compiler, settings and alignment
â PlasmaHH
Sep 6 at 9:28
10
There is no guarantee in C that a structure copying process cannot be interrupted. However, the interrupt is usually supposed to return to the point in the code where the copying process can complete. So it probably doesn't matter unless the interrupt code depends upon it for some reason (unlikely in most circumstances.) If these structures are part of a upper/lower interrupt driver pair, though, then this could be a problem if the upper level is in the process of removing or adding a "chunk" to a buffer when an interrupt takes place that must also cope with "chunks" in the same buffer.
â jonk
Sep 6 at 9:35
4
@jonk: Please do not answer the question in comments, as this bypasses the normal review process for answers, as discussed in meta
â Dave Tweedâ¦
Sep 6 at 18:50
6
@DaveTweed Then you and this site will lose my comments. I don't write answers unless I have the time to write fuller ones. It's my only way of operation and I won't change it. If I feel I have enough time for a "proper answer" by my definition of it, I will continue as before. But I'm working very hard on several different active projects and do NOT have the time for my usual level of answer context and content. So either I write short comments as comments, or the site loses any access to my time. Your call. My time is given on my terms, or not at all.
â jonk
Sep 6 at 18:57
4
@jonk: There's nothing wrong with writing a short answer as long as it is complete and self-contained, like your comment is. Your commitment to lengthy answers is entirely on you. The site has rules and processes, and I'm just trying to nudge you in the right direction. Ultimately, it's entirely up to you -- you could have had 9 upvotes (+90 rep) on your answer...
â Dave Tweedâ¦
Sep 6 at 20:08
17
17
There isn't really a "copy process", there will be instructions copying bytes around and if they are not atomic they can be interrupted, depends on your architecture, compiler, settings and alignment
â PlasmaHH
Sep 6 at 9:28
There isn't really a "copy process", there will be instructions copying bytes around and if they are not atomic they can be interrupted, depends on your architecture, compiler, settings and alignment
â PlasmaHH
Sep 6 at 9:28
10
10
There is no guarantee in C that a structure copying process cannot be interrupted. However, the interrupt is usually supposed to return to the point in the code where the copying process can complete. So it probably doesn't matter unless the interrupt code depends upon it for some reason (unlikely in most circumstances.) If these structures are part of a upper/lower interrupt driver pair, though, then this could be a problem if the upper level is in the process of removing or adding a "chunk" to a buffer when an interrupt takes place that must also cope with "chunks" in the same buffer.
â jonk
Sep 6 at 9:35
There is no guarantee in C that a structure copying process cannot be interrupted. However, the interrupt is usually supposed to return to the point in the code where the copying process can complete. So it probably doesn't matter unless the interrupt code depends upon it for some reason (unlikely in most circumstances.) If these structures are part of a upper/lower interrupt driver pair, though, then this could be a problem if the upper level is in the process of removing or adding a "chunk" to a buffer when an interrupt takes place that must also cope with "chunks" in the same buffer.
â jonk
Sep 6 at 9:35
4
4
@jonk: Please do not answer the question in comments, as this bypasses the normal review process for answers, as discussed in meta
â Dave Tweedâ¦
Sep 6 at 18:50
@jonk: Please do not answer the question in comments, as this bypasses the normal review process for answers, as discussed in meta
â Dave Tweedâ¦
Sep 6 at 18:50
6
6
@DaveTweed Then you and this site will lose my comments. I don't write answers unless I have the time to write fuller ones. It's my only way of operation and I won't change it. If I feel I have enough time for a "proper answer" by my definition of it, I will continue as before. But I'm working very hard on several different active projects and do NOT have the time for my usual level of answer context and content. So either I write short comments as comments, or the site loses any access to my time. Your call. My time is given on my terms, or not at all.
â jonk
Sep 6 at 18:57
@DaveTweed Then you and this site will lose my comments. I don't write answers unless I have the time to write fuller ones. It's my only way of operation and I won't change it. If I feel I have enough time for a "proper answer" by my definition of it, I will continue as before. But I'm working very hard on several different active projects and do NOT have the time for my usual level of answer context and content. So either I write short comments as comments, or the site loses any access to my time. Your call. My time is given on my terms, or not at all.
â jonk
Sep 6 at 18:57
4
4
@jonk: There's nothing wrong with writing a short answer as long as it is complete and self-contained, like your comment is. Your commitment to lengthy answers is entirely on you. The site has rules and processes, and I'm just trying to nudge you in the right direction. Ultimately, it's entirely up to you -- you could have had 9 upvotes (+90 rep) on your answer...
â Dave Tweedâ¦
Sep 6 at 20:08
@jonk: There's nothing wrong with writing a short answer as long as it is complete and self-contained, like your comment is. Your commitment to lengthy answers is entirely on you. The site has rules and processes, and I'm just trying to nudge you in the right direction. Ultimately, it's entirely up to you -- you could have had 9 upvotes (+90 rep) on your answer...
â Dave Tweedâ¦
Sep 6 at 20:08
 |Â
show 8 more comments
7 Answers
7
active
oldest
votes
up vote
24
down vote
accepted
Yes. Pretty much everything in an MCU can be interrupted by an interrupt request. When the interrupt handler completes the previous code will just continue so it is usually not a problem.
In a special case the interrupt handlers can be interrupted themselves by interrupts of higher priorities (nested interrupts).
If a series of instructions must not be interrupted then you need to implement a critical section (basically globally disable interrupts, do the job, enable again).
Remember that depending on architecture of the target CPU a single line of C can be compiled to many assembly instructions. A simple i++
on an AVR is compiled to multiple instructions if i
is for example uint32_t
.
1
Regarding your last paragraph, I assume that's only true on 16/8 bit systems, right? I know you're saying AVR.. just making sure.
â Harry Svensson
Sep 6 at 11:34
1
memcpy of a struct (like in the question) is multiple instructions on 32-bit ARM too. Incrementation of uint64_t on 32-bit ARM is also not atomic. Bitwise operations are also read-modify-write (unless bit-banding is used).
â filo
Sep 6 at 11:36
4
@HarrySvensson no - on any RMW architecture and most of the uCs are Read - Modify - Write ones (mostof the RISC procesoors are RMW) . So i++ will generate in many cases (except if the value is just kept in the register which is not the case here) three instructions on the modern 32/64 bits ARM uCs as well.
â P__J__
Sep 6 at 11:38
Ah, there's been a slight misunderstanding here. I was thinking about taking care of the carry when performing increments (overflow), and both of you are talking about retrieving from memory and writing back. - Oh well.
â Harry Svensson
Sep 6 at 11:48
1
In general: all operations on types wider than the data bus width are "funky".
â filo
Sep 6 at 11:50
add a comment |Â
up vote
11
down vote
Any operation that is not atomic can be interfered with by an interrupt. This kind of programming is often very different than most other programming and can be confusing to people who haven't studied processor design or computer architecture.
You may think to yourself "This will never actually happen, how long does this code take to copy and how likely is an interrupt?" But with most production embedded applications it will happen because the product is on for years without updates.
The other issue with struct copies like this is when they do happen they are extraordinarily difficult to debug because they only happen when the interrupt occurs at just the right time (which can be as little as one cycle).
add a comment |Â
up vote
10
down vote
The whole point of interrupts is that they can (and do) happen all the time, and are designed to have zero impact on any code that happens to be running when they occur. All the registers are saved, and depending on the CPU architecture, a completely different register set may be swapped in, the interrupt does its thing, and then the original registers are restored and the code continues to run as normal.
Problems can occur when the interrupt service routine itself tries to access memory that is being accessed by the running, interrupted code.
Even more subtle errors can occur when a time-critical I/O process is interrupted. These problems are commonplace with older, simpler, less secure architectures where there may be little separation between "user" and "supervisor/kernel" mode code.
This kind of problem can be hard to identify, and often difficult to reproduce, but once identified they're often fairly trivial to fix using defensive programming, mutexes/semaphores or simply by disabling interrupts in critical sections of code.
The general class of problems has been studied extensively, and modern multi-core CPUs and even multi-tasking operating systems would not be possible if multiple solutions were not already tried and tested.
New contributor
add a comment |Â
up vote
4
down vote
I'm just going to go ahead and assume you asked this for a very good reason.
*Data_external = Data_internal;
Can be split (barring some edge cases that are unlikely to be in play here).
I don't know your CPU but I haven't seen a CPU yet that can't do the moral equivalent of:
cli(); /* mask all interrupts */
*Data_external = Data_internal;
sti(); /* restore interrupt mask */
Now it can't be split on any single core CPU because nothing can interrupt while interrupts are off. Whether or not this is a good idea depends on a lot of things that I'm simply not qualified to evaluate.
If you are multi-core (and I finally remembered there is a multi-core embedded CPU on the market) don't do this. It is worthless. You would need to develop proper locking.
What are cli and sti? from google they appear to be x86 instructions?
â Sam
Sep 7 at 2:41
@Sam: Well yes, those are the names of the instructions in x86. I think they have the same names in the PDP-11 because some code that originated there had the same function names for a logical equivalent in usermode (mask inter-process signals). Here's instructions for Arduino: tldp.org/LDP/tlk/dd/interrupts.html
â Joshua
Sep 7 at 3:25
3
Normally you would disable interrupts, but only reenable them if they were actually enabled. Otherwise your code has the side-effrct of always enabling interrupts, even if they were disabled before the code was called.
â Tom Carpenter
Sep 7 at 13:15
add a comment |Â
up vote
3
down vote
The code as you presented it indeed can be interrupted. However, before you start making critical sections all over the place, you should check a few things:
You say this function is "inside a driver". Are interrupts already disabled when this function is called? Or is it called inside an interrupt handler which prevents other interrupts from triggering? If yes, the operation cannot in fact be interrupted.
Is
Data_internal
ever accessed inside an interrupt handler? If not, there is no harm even if the operation can be interrupted.
add a comment |Â
up vote
0
down vote
[Not enough rep to comment]
Another gotchya with that kind of struct copy is that it is a shallow copy. You may need a deep copy instead.
A shallow copy could possibly but not likely be atomic, depending on machine architecture. A deep copy is almost certainly not atomic on any architecture.
New contributor
A fair point; but a deep copy is more likely to be atomic because it's almost always put in place by a pointer swap. Yet in this case, if it should have been a deep copy it will definitely not be atomic.
â Joshua
Sep 7 at 23:21
add a comment |Â
up vote
0
down vote
A quality implementation suitable for embedded-systems use will document how volatile
-qualified reads or writes of various types will be performed in sufficient detail to indicate whether and how they may be "split" by interrupts, and also whether or not volatile reads and writes are sequenced with regard to non-qualified reads and writes. While some implementations may behave as though all reads and writes are volatile
-qualified, implementations are generally expected to be free to process sequences of non-qualified reads and writes in whatever fashion would be most efficient when there are no intervening volatile
accesses.
On a typical 32-bit microcontroller, reads and writes of volatile
-qualified integer types that are 32 bits and smaller; an assignment will consist of an atomic read followed by an atomic write. If you want to ensure that a 32-bit structure is copied atomically, place it in a union with a uint32_t
, and read or write that member to read or write the structure as a whole. Quality implementations that are configured to be suitable for embedded systems use will allow unions to be employed in such fashion without regard for whether the Standard would require implementations that aren't intended for such use to do likewise. Note that gcc and clang will not reliably behave as quality implementations suitable for embedded systems use unless various optimizations are disabled.
add a comment |Â
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
24
down vote
accepted
Yes. Pretty much everything in an MCU can be interrupted by an interrupt request. When the interrupt handler completes the previous code will just continue so it is usually not a problem.
In a special case the interrupt handlers can be interrupted themselves by interrupts of higher priorities (nested interrupts).
If a series of instructions must not be interrupted then you need to implement a critical section (basically globally disable interrupts, do the job, enable again).
Remember that depending on architecture of the target CPU a single line of C can be compiled to many assembly instructions. A simple i++
on an AVR is compiled to multiple instructions if i
is for example uint32_t
.
1
Regarding your last paragraph, I assume that's only true on 16/8 bit systems, right? I know you're saying AVR.. just making sure.
â Harry Svensson
Sep 6 at 11:34
1
memcpy of a struct (like in the question) is multiple instructions on 32-bit ARM too. Incrementation of uint64_t on 32-bit ARM is also not atomic. Bitwise operations are also read-modify-write (unless bit-banding is used).
â filo
Sep 6 at 11:36
4
@HarrySvensson no - on any RMW architecture and most of the uCs are Read - Modify - Write ones (mostof the RISC procesoors are RMW) . So i++ will generate in many cases (except if the value is just kept in the register which is not the case here) three instructions on the modern 32/64 bits ARM uCs as well.
â P__J__
Sep 6 at 11:38
Ah, there's been a slight misunderstanding here. I was thinking about taking care of the carry when performing increments (overflow), and both of you are talking about retrieving from memory and writing back. - Oh well.
â Harry Svensson
Sep 6 at 11:48
1
In general: all operations on types wider than the data bus width are "funky".
â filo
Sep 6 at 11:50
add a comment |Â
up vote
24
down vote
accepted
Yes. Pretty much everything in an MCU can be interrupted by an interrupt request. When the interrupt handler completes the previous code will just continue so it is usually not a problem.
In a special case the interrupt handlers can be interrupted themselves by interrupts of higher priorities (nested interrupts).
If a series of instructions must not be interrupted then you need to implement a critical section (basically globally disable interrupts, do the job, enable again).
Remember that depending on architecture of the target CPU a single line of C can be compiled to many assembly instructions. A simple i++
on an AVR is compiled to multiple instructions if i
is for example uint32_t
.
1
Regarding your last paragraph, I assume that's only true on 16/8 bit systems, right? I know you're saying AVR.. just making sure.
â Harry Svensson
Sep 6 at 11:34
1
memcpy of a struct (like in the question) is multiple instructions on 32-bit ARM too. Incrementation of uint64_t on 32-bit ARM is also not atomic. Bitwise operations are also read-modify-write (unless bit-banding is used).
â filo
Sep 6 at 11:36
4
@HarrySvensson no - on any RMW architecture and most of the uCs are Read - Modify - Write ones (mostof the RISC procesoors are RMW) . So i++ will generate in many cases (except if the value is just kept in the register which is not the case here) three instructions on the modern 32/64 bits ARM uCs as well.
â P__J__
Sep 6 at 11:38
Ah, there's been a slight misunderstanding here. I was thinking about taking care of the carry when performing increments (overflow), and both of you are talking about retrieving from memory and writing back. - Oh well.
â Harry Svensson
Sep 6 at 11:48
1
In general: all operations on types wider than the data bus width are "funky".
â filo
Sep 6 at 11:50
add a comment |Â
up vote
24
down vote
accepted
up vote
24
down vote
accepted
Yes. Pretty much everything in an MCU can be interrupted by an interrupt request. When the interrupt handler completes the previous code will just continue so it is usually not a problem.
In a special case the interrupt handlers can be interrupted themselves by interrupts of higher priorities (nested interrupts).
If a series of instructions must not be interrupted then you need to implement a critical section (basically globally disable interrupts, do the job, enable again).
Remember that depending on architecture of the target CPU a single line of C can be compiled to many assembly instructions. A simple i++
on an AVR is compiled to multiple instructions if i
is for example uint32_t
.
Yes. Pretty much everything in an MCU can be interrupted by an interrupt request. When the interrupt handler completes the previous code will just continue so it is usually not a problem.
In a special case the interrupt handlers can be interrupted themselves by interrupts of higher priorities (nested interrupts).
If a series of instructions must not be interrupted then you need to implement a critical section (basically globally disable interrupts, do the job, enable again).
Remember that depending on architecture of the target CPU a single line of C can be compiled to many assembly instructions. A simple i++
on an AVR is compiled to multiple instructions if i
is for example uint32_t
.
answered Sep 6 at 11:30
filo
5,2001929
5,2001929
1
Regarding your last paragraph, I assume that's only true on 16/8 bit systems, right? I know you're saying AVR.. just making sure.
â Harry Svensson
Sep 6 at 11:34
1
memcpy of a struct (like in the question) is multiple instructions on 32-bit ARM too. Incrementation of uint64_t on 32-bit ARM is also not atomic. Bitwise operations are also read-modify-write (unless bit-banding is used).
â filo
Sep 6 at 11:36
4
@HarrySvensson no - on any RMW architecture and most of the uCs are Read - Modify - Write ones (mostof the RISC procesoors are RMW) . So i++ will generate in many cases (except if the value is just kept in the register which is not the case here) three instructions on the modern 32/64 bits ARM uCs as well.
â P__J__
Sep 6 at 11:38
Ah, there's been a slight misunderstanding here. I was thinking about taking care of the carry when performing increments (overflow), and both of you are talking about retrieving from memory and writing back. - Oh well.
â Harry Svensson
Sep 6 at 11:48
1
In general: all operations on types wider than the data bus width are "funky".
â filo
Sep 6 at 11:50
add a comment |Â
1
Regarding your last paragraph, I assume that's only true on 16/8 bit systems, right? I know you're saying AVR.. just making sure.
â Harry Svensson
Sep 6 at 11:34
1
memcpy of a struct (like in the question) is multiple instructions on 32-bit ARM too. Incrementation of uint64_t on 32-bit ARM is also not atomic. Bitwise operations are also read-modify-write (unless bit-banding is used).
â filo
Sep 6 at 11:36
4
@HarrySvensson no - on any RMW architecture and most of the uCs are Read - Modify - Write ones (mostof the RISC procesoors are RMW) . So i++ will generate in many cases (except if the value is just kept in the register which is not the case here) three instructions on the modern 32/64 bits ARM uCs as well.
â P__J__
Sep 6 at 11:38
Ah, there's been a slight misunderstanding here. I was thinking about taking care of the carry when performing increments (overflow), and both of you are talking about retrieving from memory and writing back. - Oh well.
â Harry Svensson
Sep 6 at 11:48
1
In general: all operations on types wider than the data bus width are "funky".
â filo
Sep 6 at 11:50
1
1
Regarding your last paragraph, I assume that's only true on 16/8 bit systems, right? I know you're saying AVR.. just making sure.
â Harry Svensson
Sep 6 at 11:34
Regarding your last paragraph, I assume that's only true on 16/8 bit systems, right? I know you're saying AVR.. just making sure.
â Harry Svensson
Sep 6 at 11:34
1
1
memcpy of a struct (like in the question) is multiple instructions on 32-bit ARM too. Incrementation of uint64_t on 32-bit ARM is also not atomic. Bitwise operations are also read-modify-write (unless bit-banding is used).
â filo
Sep 6 at 11:36
memcpy of a struct (like in the question) is multiple instructions on 32-bit ARM too. Incrementation of uint64_t on 32-bit ARM is also not atomic. Bitwise operations are also read-modify-write (unless bit-banding is used).
â filo
Sep 6 at 11:36
4
4
@HarrySvensson no - on any RMW architecture and most of the uCs are Read - Modify - Write ones (mostof the RISC procesoors are RMW) . So i++ will generate in many cases (except if the value is just kept in the register which is not the case here) three instructions on the modern 32/64 bits ARM uCs as well.
â P__J__
Sep 6 at 11:38
@HarrySvensson no - on any RMW architecture and most of the uCs are Read - Modify - Write ones (mostof the RISC procesoors are RMW) . So i++ will generate in many cases (except if the value is just kept in the register which is not the case here) three instructions on the modern 32/64 bits ARM uCs as well.
â P__J__
Sep 6 at 11:38
Ah, there's been a slight misunderstanding here. I was thinking about taking care of the carry when performing increments (overflow), and both of you are talking about retrieving from memory and writing back. - Oh well.
â Harry Svensson
Sep 6 at 11:48
Ah, there's been a slight misunderstanding here. I was thinking about taking care of the carry when performing increments (overflow), and both of you are talking about retrieving from memory and writing back. - Oh well.
â Harry Svensson
Sep 6 at 11:48
1
1
In general: all operations on types wider than the data bus width are "funky".
â filo
Sep 6 at 11:50
In general: all operations on types wider than the data bus width are "funky".
â filo
Sep 6 at 11:50
add a comment |Â
up vote
11
down vote
Any operation that is not atomic can be interfered with by an interrupt. This kind of programming is often very different than most other programming and can be confusing to people who haven't studied processor design or computer architecture.
You may think to yourself "This will never actually happen, how long does this code take to copy and how likely is an interrupt?" But with most production embedded applications it will happen because the product is on for years without updates.
The other issue with struct copies like this is when they do happen they are extraordinarily difficult to debug because they only happen when the interrupt occurs at just the right time (which can be as little as one cycle).
add a comment |Â
up vote
11
down vote
Any operation that is not atomic can be interfered with by an interrupt. This kind of programming is often very different than most other programming and can be confusing to people who haven't studied processor design or computer architecture.
You may think to yourself "This will never actually happen, how long does this code take to copy and how likely is an interrupt?" But with most production embedded applications it will happen because the product is on for years without updates.
The other issue with struct copies like this is when they do happen they are extraordinarily difficult to debug because they only happen when the interrupt occurs at just the right time (which can be as little as one cycle).
add a comment |Â
up vote
11
down vote
up vote
11
down vote
Any operation that is not atomic can be interfered with by an interrupt. This kind of programming is often very different than most other programming and can be confusing to people who haven't studied processor design or computer architecture.
You may think to yourself "This will never actually happen, how long does this code take to copy and how likely is an interrupt?" But with most production embedded applications it will happen because the product is on for years without updates.
The other issue with struct copies like this is when they do happen they are extraordinarily difficult to debug because they only happen when the interrupt occurs at just the right time (which can be as little as one cycle).
Any operation that is not atomic can be interfered with by an interrupt. This kind of programming is often very different than most other programming and can be confusing to people who haven't studied processor design or computer architecture.
You may think to yourself "This will never actually happen, how long does this code take to copy and how likely is an interrupt?" But with most production embedded applications it will happen because the product is on for years without updates.
The other issue with struct copies like this is when they do happen they are extraordinarily difficult to debug because they only happen when the interrupt occurs at just the right time (which can be as little as one cycle).
answered Sep 6 at 15:25
Sam
462211
462211
add a comment |Â
add a comment |Â
up vote
10
down vote
The whole point of interrupts is that they can (and do) happen all the time, and are designed to have zero impact on any code that happens to be running when they occur. All the registers are saved, and depending on the CPU architecture, a completely different register set may be swapped in, the interrupt does its thing, and then the original registers are restored and the code continues to run as normal.
Problems can occur when the interrupt service routine itself tries to access memory that is being accessed by the running, interrupted code.
Even more subtle errors can occur when a time-critical I/O process is interrupted. These problems are commonplace with older, simpler, less secure architectures where there may be little separation between "user" and "supervisor/kernel" mode code.
This kind of problem can be hard to identify, and often difficult to reproduce, but once identified they're often fairly trivial to fix using defensive programming, mutexes/semaphores or simply by disabling interrupts in critical sections of code.
The general class of problems has been studied extensively, and modern multi-core CPUs and even multi-tasking operating systems would not be possible if multiple solutions were not already tried and tested.
New contributor
add a comment |Â
up vote
10
down vote
The whole point of interrupts is that they can (and do) happen all the time, and are designed to have zero impact on any code that happens to be running when they occur. All the registers are saved, and depending on the CPU architecture, a completely different register set may be swapped in, the interrupt does its thing, and then the original registers are restored and the code continues to run as normal.
Problems can occur when the interrupt service routine itself tries to access memory that is being accessed by the running, interrupted code.
Even more subtle errors can occur when a time-critical I/O process is interrupted. These problems are commonplace with older, simpler, less secure architectures where there may be little separation between "user" and "supervisor/kernel" mode code.
This kind of problem can be hard to identify, and often difficult to reproduce, but once identified they're often fairly trivial to fix using defensive programming, mutexes/semaphores or simply by disabling interrupts in critical sections of code.
The general class of problems has been studied extensively, and modern multi-core CPUs and even multi-tasking operating systems would not be possible if multiple solutions were not already tried and tested.
New contributor
add a comment |Â
up vote
10
down vote
up vote
10
down vote
The whole point of interrupts is that they can (and do) happen all the time, and are designed to have zero impact on any code that happens to be running when they occur. All the registers are saved, and depending on the CPU architecture, a completely different register set may be swapped in, the interrupt does its thing, and then the original registers are restored and the code continues to run as normal.
Problems can occur when the interrupt service routine itself tries to access memory that is being accessed by the running, interrupted code.
Even more subtle errors can occur when a time-critical I/O process is interrupted. These problems are commonplace with older, simpler, less secure architectures where there may be little separation between "user" and "supervisor/kernel" mode code.
This kind of problem can be hard to identify, and often difficult to reproduce, but once identified they're often fairly trivial to fix using defensive programming, mutexes/semaphores or simply by disabling interrupts in critical sections of code.
The general class of problems has been studied extensively, and modern multi-core CPUs and even multi-tasking operating systems would not be possible if multiple solutions were not already tried and tested.
New contributor
The whole point of interrupts is that they can (and do) happen all the time, and are designed to have zero impact on any code that happens to be running when they occur. All the registers are saved, and depending on the CPU architecture, a completely different register set may be swapped in, the interrupt does its thing, and then the original registers are restored and the code continues to run as normal.
Problems can occur when the interrupt service routine itself tries to access memory that is being accessed by the running, interrupted code.
Even more subtle errors can occur when a time-critical I/O process is interrupted. These problems are commonplace with older, simpler, less secure architectures where there may be little separation between "user" and "supervisor/kernel" mode code.
This kind of problem can be hard to identify, and often difficult to reproduce, but once identified they're often fairly trivial to fix using defensive programming, mutexes/semaphores or simply by disabling interrupts in critical sections of code.
The general class of problems has been studied extensively, and modern multi-core CPUs and even multi-tasking operating systems would not be possible if multiple solutions were not already tried and tested.
New contributor
edited Sep 6 at 14:24
New contributor
answered Sep 6 at 13:39
Echelon
2015
2015
New contributor
New contributor
add a comment |Â
add a comment |Â
up vote
4
down vote
I'm just going to go ahead and assume you asked this for a very good reason.
*Data_external = Data_internal;
Can be split (barring some edge cases that are unlikely to be in play here).
I don't know your CPU but I haven't seen a CPU yet that can't do the moral equivalent of:
cli(); /* mask all interrupts */
*Data_external = Data_internal;
sti(); /* restore interrupt mask */
Now it can't be split on any single core CPU because nothing can interrupt while interrupts are off. Whether or not this is a good idea depends on a lot of things that I'm simply not qualified to evaluate.
If you are multi-core (and I finally remembered there is a multi-core embedded CPU on the market) don't do this. It is worthless. You would need to develop proper locking.
What are cli and sti? from google they appear to be x86 instructions?
â Sam
Sep 7 at 2:41
@Sam: Well yes, those are the names of the instructions in x86. I think they have the same names in the PDP-11 because some code that originated there had the same function names for a logical equivalent in usermode (mask inter-process signals). Here's instructions for Arduino: tldp.org/LDP/tlk/dd/interrupts.html
â Joshua
Sep 7 at 3:25
3
Normally you would disable interrupts, but only reenable them if they were actually enabled. Otherwise your code has the side-effrct of always enabling interrupts, even if they were disabled before the code was called.
â Tom Carpenter
Sep 7 at 13:15
add a comment |Â
up vote
4
down vote
I'm just going to go ahead and assume you asked this for a very good reason.
*Data_external = Data_internal;
Can be split (barring some edge cases that are unlikely to be in play here).
I don't know your CPU but I haven't seen a CPU yet that can't do the moral equivalent of:
cli(); /* mask all interrupts */
*Data_external = Data_internal;
sti(); /* restore interrupt mask */
Now it can't be split on any single core CPU because nothing can interrupt while interrupts are off. Whether or not this is a good idea depends on a lot of things that I'm simply not qualified to evaluate.
If you are multi-core (and I finally remembered there is a multi-core embedded CPU on the market) don't do this. It is worthless. You would need to develop proper locking.
What are cli and sti? from google they appear to be x86 instructions?
â Sam
Sep 7 at 2:41
@Sam: Well yes, those are the names of the instructions in x86. I think they have the same names in the PDP-11 because some code that originated there had the same function names for a logical equivalent in usermode (mask inter-process signals). Here's instructions for Arduino: tldp.org/LDP/tlk/dd/interrupts.html
â Joshua
Sep 7 at 3:25
3
Normally you would disable interrupts, but only reenable them if they were actually enabled. Otherwise your code has the side-effrct of always enabling interrupts, even if they were disabled before the code was called.
â Tom Carpenter
Sep 7 at 13:15
add a comment |Â
up vote
4
down vote
up vote
4
down vote
I'm just going to go ahead and assume you asked this for a very good reason.
*Data_external = Data_internal;
Can be split (barring some edge cases that are unlikely to be in play here).
I don't know your CPU but I haven't seen a CPU yet that can't do the moral equivalent of:
cli(); /* mask all interrupts */
*Data_external = Data_internal;
sti(); /* restore interrupt mask */
Now it can't be split on any single core CPU because nothing can interrupt while interrupts are off. Whether or not this is a good idea depends on a lot of things that I'm simply not qualified to evaluate.
If you are multi-core (and I finally remembered there is a multi-core embedded CPU on the market) don't do this. It is worthless. You would need to develop proper locking.
I'm just going to go ahead and assume you asked this for a very good reason.
*Data_external = Data_internal;
Can be split (barring some edge cases that are unlikely to be in play here).
I don't know your CPU but I haven't seen a CPU yet that can't do the moral equivalent of:
cli(); /* mask all interrupts */
*Data_external = Data_internal;
sti(); /* restore interrupt mask */
Now it can't be split on any single core CPU because nothing can interrupt while interrupts are off. Whether or not this is a good idea depends on a lot of things that I'm simply not qualified to evaluate.
If you are multi-core (and I finally remembered there is a multi-core embedded CPU on the market) don't do this. It is worthless. You would need to develop proper locking.
edited Sep 7 at 3:26
answered Sep 6 at 23:32
Joshua
21115
21115
What are cli and sti? from google they appear to be x86 instructions?
â Sam
Sep 7 at 2:41
@Sam: Well yes, those are the names of the instructions in x86. I think they have the same names in the PDP-11 because some code that originated there had the same function names for a logical equivalent in usermode (mask inter-process signals). Here's instructions for Arduino: tldp.org/LDP/tlk/dd/interrupts.html
â Joshua
Sep 7 at 3:25
3
Normally you would disable interrupts, but only reenable them if they were actually enabled. Otherwise your code has the side-effrct of always enabling interrupts, even if they were disabled before the code was called.
â Tom Carpenter
Sep 7 at 13:15
add a comment |Â
What are cli and sti? from google they appear to be x86 instructions?
â Sam
Sep 7 at 2:41
@Sam: Well yes, those are the names of the instructions in x86. I think they have the same names in the PDP-11 because some code that originated there had the same function names for a logical equivalent in usermode (mask inter-process signals). Here's instructions for Arduino: tldp.org/LDP/tlk/dd/interrupts.html
â Joshua
Sep 7 at 3:25
3
Normally you would disable interrupts, but only reenable them if they were actually enabled. Otherwise your code has the side-effrct of always enabling interrupts, even if they were disabled before the code was called.
â Tom Carpenter
Sep 7 at 13:15
What are cli and sti? from google they appear to be x86 instructions?
â Sam
Sep 7 at 2:41
What are cli and sti? from google they appear to be x86 instructions?
â Sam
Sep 7 at 2:41
@Sam: Well yes, those are the names of the instructions in x86. I think they have the same names in the PDP-11 because some code that originated there had the same function names for a logical equivalent in usermode (mask inter-process signals). Here's instructions for Arduino: tldp.org/LDP/tlk/dd/interrupts.html
â Joshua
Sep 7 at 3:25
@Sam: Well yes, those are the names of the instructions in x86. I think they have the same names in the PDP-11 because some code that originated there had the same function names for a logical equivalent in usermode (mask inter-process signals). Here's instructions for Arduino: tldp.org/LDP/tlk/dd/interrupts.html
â Joshua
Sep 7 at 3:25
3
3
Normally you would disable interrupts, but only reenable them if they were actually enabled. Otherwise your code has the side-effrct of always enabling interrupts, even if they were disabled before the code was called.
â Tom Carpenter
Sep 7 at 13:15
Normally you would disable interrupts, but only reenable them if they were actually enabled. Otherwise your code has the side-effrct of always enabling interrupts, even if they were disabled before the code was called.
â Tom Carpenter
Sep 7 at 13:15
add a comment |Â
up vote
3
down vote
The code as you presented it indeed can be interrupted. However, before you start making critical sections all over the place, you should check a few things:
You say this function is "inside a driver". Are interrupts already disabled when this function is called? Or is it called inside an interrupt handler which prevents other interrupts from triggering? If yes, the operation cannot in fact be interrupted.
Is
Data_internal
ever accessed inside an interrupt handler? If not, there is no harm even if the operation can be interrupted.
add a comment |Â
up vote
3
down vote
The code as you presented it indeed can be interrupted. However, before you start making critical sections all over the place, you should check a few things:
You say this function is "inside a driver". Are interrupts already disabled when this function is called? Or is it called inside an interrupt handler which prevents other interrupts from triggering? If yes, the operation cannot in fact be interrupted.
Is
Data_internal
ever accessed inside an interrupt handler? If not, there is no harm even if the operation can be interrupted.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
The code as you presented it indeed can be interrupted. However, before you start making critical sections all over the place, you should check a few things:
You say this function is "inside a driver". Are interrupts already disabled when this function is called? Or is it called inside an interrupt handler which prevents other interrupts from triggering? If yes, the operation cannot in fact be interrupted.
Is
Data_internal
ever accessed inside an interrupt handler? If not, there is no harm even if the operation can be interrupted.
The code as you presented it indeed can be interrupted. However, before you start making critical sections all over the place, you should check a few things:
You say this function is "inside a driver". Are interrupts already disabled when this function is called? Or is it called inside an interrupt handler which prevents other interrupts from triggering? If yes, the operation cannot in fact be interrupted.
Is
Data_internal
ever accessed inside an interrupt handler? If not, there is no harm even if the operation can be interrupted.
answered Sep 7 at 13:08
Dmitry Grigoryev
16.5k22770
16.5k22770
add a comment |Â
add a comment |Â
up vote
0
down vote
[Not enough rep to comment]
Another gotchya with that kind of struct copy is that it is a shallow copy. You may need a deep copy instead.
A shallow copy could possibly but not likely be atomic, depending on machine architecture. A deep copy is almost certainly not atomic on any architecture.
New contributor
A fair point; but a deep copy is more likely to be atomic because it's almost always put in place by a pointer swap. Yet in this case, if it should have been a deep copy it will definitely not be atomic.
â Joshua
Sep 7 at 23:21
add a comment |Â
up vote
0
down vote
[Not enough rep to comment]
Another gotchya with that kind of struct copy is that it is a shallow copy. You may need a deep copy instead.
A shallow copy could possibly but not likely be atomic, depending on machine architecture. A deep copy is almost certainly not atomic on any architecture.
New contributor
A fair point; but a deep copy is more likely to be atomic because it's almost always put in place by a pointer swap. Yet in this case, if it should have been a deep copy it will definitely not be atomic.
â Joshua
Sep 7 at 23:21
add a comment |Â
up vote
0
down vote
up vote
0
down vote
[Not enough rep to comment]
Another gotchya with that kind of struct copy is that it is a shallow copy. You may need a deep copy instead.
A shallow copy could possibly but not likely be atomic, depending on machine architecture. A deep copy is almost certainly not atomic on any architecture.
New contributor
[Not enough rep to comment]
Another gotchya with that kind of struct copy is that it is a shallow copy. You may need a deep copy instead.
A shallow copy could possibly but not likely be atomic, depending on machine architecture. A deep copy is almost certainly not atomic on any architecture.
New contributor
New contributor
answered Sep 7 at 18:49
studog
1
1
New contributor
New contributor
A fair point; but a deep copy is more likely to be atomic because it's almost always put in place by a pointer swap. Yet in this case, if it should have been a deep copy it will definitely not be atomic.
â Joshua
Sep 7 at 23:21
add a comment |Â
A fair point; but a deep copy is more likely to be atomic because it's almost always put in place by a pointer swap. Yet in this case, if it should have been a deep copy it will definitely not be atomic.
â Joshua
Sep 7 at 23:21
A fair point; but a deep copy is more likely to be atomic because it's almost always put in place by a pointer swap. Yet in this case, if it should have been a deep copy it will definitely not be atomic.
â Joshua
Sep 7 at 23:21
A fair point; but a deep copy is more likely to be atomic because it's almost always put in place by a pointer swap. Yet in this case, if it should have been a deep copy it will definitely not be atomic.
â Joshua
Sep 7 at 23:21
add a comment |Â
up vote
0
down vote
A quality implementation suitable for embedded-systems use will document how volatile
-qualified reads or writes of various types will be performed in sufficient detail to indicate whether and how they may be "split" by interrupts, and also whether or not volatile reads and writes are sequenced with regard to non-qualified reads and writes. While some implementations may behave as though all reads and writes are volatile
-qualified, implementations are generally expected to be free to process sequences of non-qualified reads and writes in whatever fashion would be most efficient when there are no intervening volatile
accesses.
On a typical 32-bit microcontroller, reads and writes of volatile
-qualified integer types that are 32 bits and smaller; an assignment will consist of an atomic read followed by an atomic write. If you want to ensure that a 32-bit structure is copied atomically, place it in a union with a uint32_t
, and read or write that member to read or write the structure as a whole. Quality implementations that are configured to be suitable for embedded systems use will allow unions to be employed in such fashion without regard for whether the Standard would require implementations that aren't intended for such use to do likewise. Note that gcc and clang will not reliably behave as quality implementations suitable for embedded systems use unless various optimizations are disabled.
add a comment |Â
up vote
0
down vote
A quality implementation suitable for embedded-systems use will document how volatile
-qualified reads or writes of various types will be performed in sufficient detail to indicate whether and how they may be "split" by interrupts, and also whether or not volatile reads and writes are sequenced with regard to non-qualified reads and writes. While some implementations may behave as though all reads and writes are volatile
-qualified, implementations are generally expected to be free to process sequences of non-qualified reads and writes in whatever fashion would be most efficient when there are no intervening volatile
accesses.
On a typical 32-bit microcontroller, reads and writes of volatile
-qualified integer types that are 32 bits and smaller; an assignment will consist of an atomic read followed by an atomic write. If you want to ensure that a 32-bit structure is copied atomically, place it in a union with a uint32_t
, and read or write that member to read or write the structure as a whole. Quality implementations that are configured to be suitable for embedded systems use will allow unions to be employed in such fashion without regard for whether the Standard would require implementations that aren't intended for such use to do likewise. Note that gcc and clang will not reliably behave as quality implementations suitable for embedded systems use unless various optimizations are disabled.
add a comment |Â
up vote
0
down vote
up vote
0
down vote
A quality implementation suitable for embedded-systems use will document how volatile
-qualified reads or writes of various types will be performed in sufficient detail to indicate whether and how they may be "split" by interrupts, and also whether or not volatile reads and writes are sequenced with regard to non-qualified reads and writes. While some implementations may behave as though all reads and writes are volatile
-qualified, implementations are generally expected to be free to process sequences of non-qualified reads and writes in whatever fashion would be most efficient when there are no intervening volatile
accesses.
On a typical 32-bit microcontroller, reads and writes of volatile
-qualified integer types that are 32 bits and smaller; an assignment will consist of an atomic read followed by an atomic write. If you want to ensure that a 32-bit structure is copied atomically, place it in a union with a uint32_t
, and read or write that member to read or write the structure as a whole. Quality implementations that are configured to be suitable for embedded systems use will allow unions to be employed in such fashion without regard for whether the Standard would require implementations that aren't intended for such use to do likewise. Note that gcc and clang will not reliably behave as quality implementations suitable for embedded systems use unless various optimizations are disabled.
A quality implementation suitable for embedded-systems use will document how volatile
-qualified reads or writes of various types will be performed in sufficient detail to indicate whether and how they may be "split" by interrupts, and also whether or not volatile reads and writes are sequenced with regard to non-qualified reads and writes. While some implementations may behave as though all reads and writes are volatile
-qualified, implementations are generally expected to be free to process sequences of non-qualified reads and writes in whatever fashion would be most efficient when there are no intervening volatile
accesses.
On a typical 32-bit microcontroller, reads and writes of volatile
-qualified integer types that are 32 bits and smaller; an assignment will consist of an atomic read followed by an atomic write. If you want to ensure that a 32-bit structure is copied atomically, place it in a union with a uint32_t
, and read or write that member to read or write the structure as a whole. Quality implementations that are configured to be suitable for embedded systems use will allow unions to be employed in such fashion without regard for whether the Standard would require implementations that aren't intended for such use to do likewise. Note that gcc and clang will not reliably behave as quality implementations suitable for embedded systems use unless various optimizations are disabled.
answered Sep 7 at 18:51
supercat
36.9k157106
36.9k157106
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2felectronics.stackexchange.com%2fquestions%2f394614%2fis-it-possible-to-interrupt-the-copy-process-of-a-struct-by-an-interrupt-in-embe%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
17
There isn't really a "copy process", there will be instructions copying bytes around and if they are not atomic they can be interrupted, depends on your architecture, compiler, settings and alignment
â PlasmaHH
Sep 6 at 9:28
10
There is no guarantee in C that a structure copying process cannot be interrupted. However, the interrupt is usually supposed to return to the point in the code where the copying process can complete. So it probably doesn't matter unless the interrupt code depends upon it for some reason (unlikely in most circumstances.) If these structures are part of a upper/lower interrupt driver pair, though, then this could be a problem if the upper level is in the process of removing or adding a "chunk" to a buffer when an interrupt takes place that must also cope with "chunks" in the same buffer.
â jonk
Sep 6 at 9:35
4
@jonk: Please do not answer the question in comments, as this bypasses the normal review process for answers, as discussed in meta
â Dave Tweedâ¦
Sep 6 at 18:50
6
@DaveTweed Then you and this site will lose my comments. I don't write answers unless I have the time to write fuller ones. It's my only way of operation and I won't change it. If I feel I have enough time for a "proper answer" by my definition of it, I will continue as before. But I'm working very hard on several different active projects and do NOT have the time for my usual level of answer context and content. So either I write short comments as comments, or the site loses any access to my time. Your call. My time is given on my terms, or not at all.
â jonk
Sep 6 at 18:57
4
@jonk: There's nothing wrong with writing a short answer as long as it is complete and self-contained, like your comment is. Your commitment to lengthy answers is entirely on you. The site has rules and processes, and I'm just trying to nudge you in the right direction. Ultimately, it's entirely up to you -- you could have had 9 upvotes (+90 rep) on your answer...
â Dave Tweedâ¦
Sep 6 at 20:08