¿Es posible interrumpir el proceso de copia de una estructura mediante una interrupción en C incrustado?

Dentro del controlador tengo una función para copiar los datos de la estructura interna en una estructura de la aplicación.

¿Puede este proceso ser interrumpido por un disparador de interrupción del microcontrolador?

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;
}
Realmente no hay un "proceso de copia", habrá instrucciones para copiar bytes y, si no son atómicos, pueden interrumpirse, depende de su arquitectura, compilador, configuración y alineación.
No hay garantía en C de que no se pueda interrumpir un proceso de copia de estructura. Sin embargo, generalmente se supone que la interrupción regresa al punto en el código donde se puede completar el proceso de copia. Por lo tanto, probablemente no importe a menos que el código de interrupción dependa de él por alguna razón (poco probable en la mayoría de las circunstancias). Sin embargo, si estas estructuras son parte de un par de controladores de interrupción superior/inferior, esto podría ser un problema si el nivel superior está en el proceso de eliminar o agregar un "fragmento" a un búfer cuando se produce una interrupción que también debe hacer frente a los "fragmentos" en el mismo búfer.
@jonk: no responda la pregunta en los comentarios, ya que esto omite el proceso normal de revisión de respuestas, como se explica en meta
@DaveTweed Entonces usted y este sitio perderán mis comentarios. No escribo respuestas a menos que tenga tiempo para escribir otras más completas. Es mi única forma de operar y no la cambiaré. Si siento que tengo suficiente tiempo para una "respuesta adecuada" según mi definición, continuaré como antes. Pero estoy trabajando muy duro en varios proyectos activos diferentes y NO tengo tiempo para mi nivel habitual de contexto y contenido de respuesta. Entonces, o escribo comentarios cortos como comentarios, o el sitio pierde acceso a mi tiempo. Tu llamada. Mi tiempo se da en mis términos, o no se da en absoluto.
@jonk: No hay nada de malo en escribir una respuesta breve siempre que sea completa y autónoma, como lo es su comentario. Su compromiso con las respuestas extensas depende completamente de usted. El sitio tiene reglas y procesos, y solo intento guiarte en la dirección correcta. En última instancia, depende completamente de usted: podría haber obtenido 9 votos a favor (+90 representantes) en su respuesta...
@DaveTweed Gracias por el empujón. Los puntos son en su mayoría irrelevantes. Creo que una vez que llegué a los "anuncios reducidos" de 200 pts, no me importó el resto (ni lo usé). Tampoco creo que merezca los números altos que tengo ahora. Solo soy un aficionado, por el amor de Dios. Y me preocupa mucho que la gente pueda confundir ese número de reputación como si significara más de lo que debería para ellos. Preferiría que mis palabras siempre se mantuvieran como "sospechosas" y merecedoras de críticas, no tomadas como una especie de evangelio. Si pudiera reducir mis números de repetición, lo haría.
@jonk Si realmente desea que las personas puedan "sospechar" de sus respuestas, permita que las voten correctamente. En el caso (¡poco probable!) de que publique algo incorrecto como comentario, los usuarios no podrán votar negativamente. Esto puede ser especialmente un problema si las personas votan a favor de un comentario que inicialmente parece correcto (de nuevo, no es que esté cuestionando la calidad de sus comentarios/respuestas :))
@mbrig Puede que me malinterpretes. Tomo la decisión de escribir solo respuestas como tales y con mi nombre adjunto si incluyen contexto y contenido completo o si creo que puedo proporcionar un enfoque inusual o único . También siempre se investigan, en el sentido de que no publicaré una respuesta antes de haberme verificado dos veces al encontrar referencias y material de apoyo que esté de acuerdo con mi posición y también que pueda citar, cuando se me pregunte. No solo escribo. Escribo, luego investigo, cotejo y verifico. Luego publica. De lo contrario, no aparece como una respuesta mía.
@mbrig Finalmente, mi número de representante no es significativo. Lo que escribo puede ser. Pero ese es un tema aparte. Ojalá pudiera dejar en blanco o deshacerme de mi número de representante. Estoy feliz de que algunas personas hayan encontrado una respuesta mía (o dos) tan útil. Pero hay una tendencia natural en la gente a imaginarse otra cosa dado mi número de representante y desearía que no lo hicieran. Eso es todo. Su sugerencia no aborda ninguna de mis preocupaciones.
@jonk: podría iniciar una pregunta de recompensa y recompensar a alguien con 29k de reputación para deshacerse de él;)
@Rev1.0 Podría hacer eso si no fuera necesario pensar demasiado en inventar un problema/pregunta que valiera la pena y tal vez tampoco falló en eliminar el problema que estoy señalando, sino que simplemente lo transmití. a otra persona (lo que no aborda mis preocupaciones). Sin embargo, es una buena muestra creativa. ;)
@jonk: Jeje, volvámonos locos entonces ;) 1. Crea la segunda cuenta 2. Escribe una pregunta increíble + recompensa con la primera cuenta 3. Responde la pregunta publicando una respuesta increíble usando la segunda cuenta 4. Elimina la segunda cuenta -> Resultado: Escribiste una buena pregunta, una buena respuesta e incluso perdiste reputación mientras lo hacías... todo lo que siempre quisiste;)
@Rev1.0 (1) Tengo el presentimiento de que esto violaría alguna interpretación de la política y me prohibiría. (2) Todavía me gustaría que la gente supiera quién soy y cambiar de cuenta complica bastante o anula este objetivo. (3) Alguien (incluso si soy yo) todavía termina con esos puntos de repetición. (4) ¡Me encanta el pensamiento creativo! Gracias.

Respuestas (7)

Sí. Prácticamente todo en una MCU puede ser interrumpido por una solicitud de interrupción. Cuando el controlador de interrupciones se completa, el código anterior simplemente continuará, por lo que generalmente no es un problema.

En un caso especial, los manejadores de interrupciones pueden ser interrumpidos por interrupciones de mayor prioridad (interrupciones anidadas).

Si no se debe interrumpir una serie de instrucciones, debe implementar una sección crítica (básicamente, deshabilitar globalmente las interrupciones, hacer el trabajo, habilitar nuevamente).

Recuerde que, según la arquitectura de la CPU de destino, una sola línea de C se puede compilar en muchas instrucciones de ensamblaje. Un simple i++en un AVR se compila en varias instrucciones i, por ejemplo uint32_t.

Con respecto a su último párrafo, supongo que eso solo es cierto en sistemas de 16/8 bits, ¿verdad? Sé que estás diciendo AVR... solo para asegurarte.
memcpy de una estructura (como en la pregunta) también son varias instrucciones en ARM de 32 bits. La incrementación de uint64_t en ARM de 32 bits tampoco es atómica. Las operaciones bit a bit también son de lectura, modificación y escritura (a menos que se utilicen bandas de bits).
@HarrySvensson no, en ninguna arquitectura RMW y la mayoría de los uC son de lectura, modificación y escritura (la mayoría de los procesadores RISC son RMW). Por lo tanto, i++ generará en muchos casos (excepto si el valor se mantiene en el registro, que no es el caso aquí) tres instrucciones en los modernos uC ARM de 32/64 bits también.
Ah, ha habido un pequeño malentendido aquí. Estaba pensando en encargarme del acarreo al realizar incrementos (desbordamiento), y ambos están hablando de recuperar de la memoria y escribir de nuevo. - Oh bien.
En general: todas las operaciones en tipos más anchos que el ancho del bus de datos son "funky".

Cualquier operación que no sea atómica puede ser interferida por una interrupción. Este tipo de programación a menudo es muy diferente a la mayoría de la programación y puede resultar confuso para las personas que no han estudiado diseño de procesadores o arquitectura de computadoras.

Puede pensar para sí mismo "Esto nunca sucederá realmente, ¿cuánto tiempo lleva copiar este código y qué probabilidad hay de una interrupción?" Pero con la mayoría de las aplicaciones integradas de producción sucederá porque el producto está encendido durante años sin actualizaciones.

El otro problema con las copias de estructura como esta es que cuando ocurren, son extraordinariamente difíciles de depurar porque solo ocurren cuando la interrupción ocurre en el momento justo (que puede ser tan solo un ciclo).

El punto central de las interrupciones es que pueden ocurrir (y ocurren) todo el tiempo, y están diseñadas para tener un impacto cero en cualquier código que se esté ejecutando cuando ocurran. Todos los registros se guardan y, según la arquitectura de la CPU, se puede intercambiar un conjunto de registros completamente diferente, la interrupción hace lo suyo y luego se restauran los registros originales y el código continúa ejecutándose normalmente.

Pueden ocurrir problemas cuando la propia rutina de servicio de interrupción intenta acceder a la memoria a la que accede el código interrumpido en ejecución. Incluso pueden ocurrir errores más sutiles cuando se interrumpe un proceso de E/S de tiempo crítico. Estos problemas son comunes con arquitecturas más antiguas, más simples y menos seguras donde puede haber poca separación entre el código de modo "usuario" y "supervisor/núcleo".

Este tipo de problema puede ser difícil de identificar y, a menudo, difícil de reproducir, pero una vez identificados, a menudo son bastante triviales de solucionar utilizando programación defensiva, mutexes/semáforos o simplemente desactivando interrupciones en secciones críticas del código.

La clase general de problemas se ha estudiado ampliamente, y las CPU multinúcleo modernas e incluso los sistemas operativos multitarea no serían posibles si no se probaran y probaran varias soluciones.

Voy a seguir adelante y asumir que preguntaste esto por una muy buena razón.

*Data_external = Data_internal;

Se puede dividir (salvo algunos casos extremos que es poco probable que estén en juego aquí).

No conozco su CPU, pero aún no he visto una CPU que no pueda hacer el equivalente moral de:

cli(); /* mask all interrupts */
*Data_external = Data_internal;
sti(); /* restore interrupt mask */

Ahora no se puede dividir en ninguna CPU de un solo núcleo porque nada puede interrumpir mientras las interrupciones están desactivadas. Si esto es una buena idea o no depende de muchas cosas que simplemente no estoy calificado para evaluar.

Si tiene varios núcleos (y finalmente recordé que hay una CPU integrada de varios núcleos en el mercado), no haga esto. No tiene valor. Necesitaría desarrollar un bloqueo adecuado.

¿Qué son cli y sti? de google parecen ser instrucciones x86?
@Sam: Bueno, sí, esos son los nombres de las instrucciones en x86. Creo que tienen los mismos nombres en el PDP-11 porque algún código que se originó allí tenía los mismos nombres de función para un equivalente lógico en modo usuario (enmascarar señales entre procesos). Aquí hay instrucciones para Arduino: tldp.org/LDP/tlk/dd/interrupts.html
Normalmente deshabilitaría las interrupciones, pero solo las volvería a habilitar si realmente estuvieran habilitadas. De lo contrario, su código tiene el efecto secundario de habilitar siempre las interrupciones, incluso si se deshabilitaron antes de llamar al código.

El código tal como lo presentaste de hecho puede ser interrumpido. Sin embargo, antes de comenzar a hacer secciones críticas por todas partes, debe verificar algunas cosas:

  • Dices que esta función está "dentro de un controlador". ¿Las interrupciones ya están deshabilitadas cuando se llama a esta función? ¿O se llama dentro de un controlador de interrupciones que evita que se activen otras interrupciones? En caso afirmativo, la operación no se puede interrumpir de hecho.

  • ¿Se Data_internalaccede alguna vez dentro de un controlador de interrupción? Si no, no hay daño incluso si la operación puede interrumpirse.

[No hay suficiente representante para comentar]

Otro problema con ese tipo de copia de estructura es que es una copia superficial . Es posible que necesite una copia profunda en su lugar.

Una copia superficial podría, pero no probablemente, ser atómica, dependiendo de la arquitectura de la máquina. Es casi seguro que una copia profunda no es atómica en ninguna arquitectura.

Un punto justo; pero es más probable que una copia profunda sea atómica porque casi siempre se establece mediante un intercambio de puntero. Sin embargo, en este caso, si debería haber sido una copia profunda, definitivamente no será atómica.

Una implementación de calidad adecuada para el uso de sistemas integrados documentará cómo volatilese realizarán las lecturas o escrituras calificadas de varios tipos con suficiente detalle para indicar si pueden ser "divididas" por interrupciones y cómo, y también si las lecturas y escrituras volátiles son o no. secuenciado con respecto a las lecturas y escrituras no calificadas. Si bien algunas implementaciones pueden comportarse como si todas las lecturas y escrituras estuvieran volatilecalificadas, generalmente se espera que las implementaciones sean libres para procesar secuencias de lecturas y escrituras no calificadas de la manera que sea más eficiente cuando no hay volatileaccesos intermedios.

En un microcontrolador típico de 32 bits, lee y escribe volatiletipos enteros calificados de 32 bits o menos; una asignación consistirá en una lectura atómica seguida de una escritura atómica. Si desea asegurarse de que una estructura de 32 bits se copie atómicamente, colóquela en una unión con uint32_ty lea o escriba ese miembro para leer o escribir la estructura como un todo. Las implementaciones de calidad que están configuradas para ser adecuadas para el uso de sistemas integrados permitirán que las uniones se empleen de esa manera sin tener en cuenta si el estándar exigiría que las implementaciones que no están destinadas para tal uso hagan lo mismo. Tenga en cuenta que gcc y clang no se comportarán de manera confiable como implementaciones de calidad adecuadas para el uso de sistemas integrados a menos que se deshabiliten varias optimizaciones.