user57735: The ADXL345, for example, requires that interrupts are responded to by querying the INT_SOURCE (interrupt source) register. In example code for the SparkFun ADXL345 Arduino Library, there is code that looks like:
void ADXL_ISR() {
  // getInterruptSource clears all triggered actions after returning value
  // Do not call again until you need to recheck for triggered actions
  byte interrupts = adxl.getInterruptSource();

  // Free Fall Detection
  if(adxl.triggered(interrupts, ADXL345_FREE_FALL)){

However, under the covers adxl.getInterruptSource() is sending an I2C message and receiving a response. This seems to be a bad idea in an interrupt service routine (ISR). 
A possible option seems to be to turn on interrupts prior to calling adxl.getInterruptSource(), however there is much advice about not doing this (such as, Nick Gammon's informative post). I've managed to get it to work with something of the form:
void setup() {
  attachInterrupt(digitalPinToInterrupt(INT_PIN), isr, LOW);
  ...
}
void isr() { 
  detachInterrupt(digitalPinToInterrupt(INT_PIN));
  interrupts();
  byte interrupts = adxl.getInterruptSource();
  ...
  attachInterrupt(digitalPinToInterrupt(INT_PIN), isr, LOW);
}

This seems to work but I'm worried I'm missing something. Any suggestions?
EDIT: Thanks for the answers that suggest polling, however I am using a MKR1400 and wish to minimise power consumption by putting the processor into a sleep state - only waking up to process the relatively rare "activity" or "free fall" events. As pointed out by @Majenko, a combination of sleeping and polling might be used. So this really just leaves the question of why is the above a bad idea.

user2967: "What is the right way to query an I2C device from an interrupt service routine?"
The right way is to NOT query an I2C device from in ISR. Interrupt service routines should be very fast to execute. (people advise going as far as avoiding digitalWrite() and digitalRead() function calls and using port registers directly, since those functions are a little slow. Anything done on a serial line is, by definition, not fast. It takes multiple milliseconds to read or write a few characters from a serial port, which is an eternity.)
When the Arduino services an interrupt it stops doing everything else, including handling other interrupts. Your timers will stall, other sensor data will be missed, any other serial communications that are in progress when the interrupt triggers will get errors, etc.
JUST DON'T DO IT.

user3508: Majenko's answer is useful — you can simply forego the use of interrupts for this and poll the pin directly in your main loop. Especially on AVR where the external pins are exposed as registers which can be read as fast as main memory this is a reasonable approach. But what if you really want the code to be "interrupt-fast" without writing code that might deadlock an ISR handler? Given the case of a fall or impact sensor, latency might be a genuine issue. Well, there are some things you can do.
First, structure your code so that you never go too long without polling the pin. That means that every bit of code needs to either return to the main loop within an acceptably short period of time, or else needs to take on the job of periodically polling the pin itself. Large compute tasks should have polls sprinkled into them, or be broken into subtasks that can be run by a state machine in the main loop. Long delays should be rewritten in the form
start = micros();
while (micros() - start < howLong) {
  // poll the ADXL interrupt
}

or, again, avoided entirely by queuing up work for the main loop to run later, instead of calling delay.
Second, consider using direct port access for the polling. A check like if (PORTB & (1<<3)) compiles down to a bare couple of instructions, and costs 2 cycles if the interrupt isn't actually asserted (which will be the usual case). Doing if (digitalRead(port)) does a call to a function which takes around 25 times as long. It's still only a few microseconds, but if you've taken the advice of the previous step to poll as frequently as possible to minimize latency, then you don't want all of those microseconds to add up and impact the performance of other code.
Lastly, a technique that doesn't make a lot of sense for this scenario, but could be applicable if you were running on a system other than an AVR-based Arduino, or if you wanted to react to some interrupt other than a level-triggered pin interrupt: you have an ISR that doesn't do any real work, but instead sets a global volatile variable to true and then immediately returns. Then in your main code, instead of polling the port directly, you check the value of that variable. If it's true, you set it to false and then run your "interrupt handler" code. The handler runs shortly after the interrupt triggers, but it's run in an interrupts-on context where it's safe to do slower operations or operations that require timer interrupts to work. This is equivalent to the old Linux concept of "bottom halves".

user4143: Just because a pin is called "interrupt" doesn't mean that you have to read it using an interrupt input.  The INTx pins of the ADXL345 are simple "level" outputs.  All the time there is an "interrupt" pending (a signal from the ADXL345 that something has happened) the corresponding INT pin is held LOW.  It remains LOW until the interrupt has been handled by your code.
It's not something that is very brief - it's something that persists as long as you need it to.
You can just read the INTx pins with normal digitalRead() from within your loop() function (polling). Unless you really need to respond right now to an event on the ADXL345 there is no need to use an interrupt input. 

57735: <p>The <a href="https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf" rel="nofollow noreferrer">ADXL345</a>, for example, requires that interrupts are responded to by querying the <code>INT_SOURCE</code> (interrupt source) register. In example code for the <a href="https://github.com/sparkfun/SparkFun_ADXL345_Arduino_Library" rel="nofollow noreferrer">SparkFun ADXL345 Arduino Library</a>, there is code that looks like:</p>

<pre class="lang-arduino prettyprint-override"><code>void ADXL_ISR() {
  // getInterruptSource clears all triggered actions after returning value
  // Do not call again until you need to recheck for triggered actions
  byte interrupts = adxl.getInterruptSource();

  // Free Fall Detection
  if(adxl.triggered(interrupts, ADXL345_FREE_FALL)){
</code></pre>

<p>However, under the covers <code>adxl.getInterruptSource()</code> is sending an I2C message and receiving a response. This seems to be a bad idea in an interrupt service routine (ISR). </p>

<p>A possible option seems to be to turn on interrupts prior to calling <code>adxl.getInterruptSource()</code>, however there is much advice about not doing this (such as, <a href="http://www.gammon.com.au/interrupts" rel="nofollow noreferrer">Nick Gammon's informative post</a>). I've managed to get it to work with something of the form:</p>

<pre class="lang-arduino prettyprint-override"><code>void setup() {
  attachInterrupt(digitalPinToInterrupt(INT_PIN), isr, LOW);
  ...
}
void isr() { 
  detachInterrupt(digitalPinToInterrupt(INT_PIN));
  interrupts();
  byte interrupts = adxl.getInterruptSource();
  ...
  attachInterrupt(digitalPinToInterrupt(INT_PIN), isr, LOW);
}
</code></pre>

<p>This seems to work but I'm worried I'm missing something. Any suggestions?</p>

<p>EDIT: Thanks for the answers that suggest polling, however I am using a MKR1400 and wish to minimise power consumption by putting the processor into a sleep state - only waking up to process the relatively rare "activity" or "free fall" events. As pointed out by @Majenko, a combination of sleeping and polling might be used. So this really just leaves the question of <em>why</em> is the above a bad idea.</p>
 2967: <p>"What is the right way to query an I2C device from an interrupt service routine?"</p>

<p>The right way is to <strong>NOT</strong> query an I2C device from in ISR. Interrupt service routines should be <strong>very</strong> fast to execute. (people advise going as far as avoiding <code>digitalWrite()</code> and <code>digitalRead()</code> function calls and using port registers directly, since those functions are a little slow. Anything done on a serial line is, by definition, not fast. It takes multiple milliseconds to read or write a few characters from a serial port, which is an eternity.)</p>

<p>When the Arduino services an interrupt it stops doing everything else, including handling other interrupts. Your timers will stall, other sensor data will be missed, any other serial communications that are in progress when the interrupt triggers will get errors, etc.</p>

<p>JUST DON'T DO IT.</p>
 3508: <p>Majenko's answer is useful — you can simply forego the use of interrupts for this and poll the pin directly in your main loop. Especially on AVR where the external pins are exposed as registers which can be read as fast as main memory this is a reasonable approach. But what if you really want the code to be "interrupt-fast" without writing code that might deadlock an ISR handler? Given the case of a fall or impact sensor, latency might be a genuine issue. Well, there are some things you can do.</p>

<p>First, structure your code so that you never go too long without polling the pin. That means that every bit of code needs to either return to the main loop within an acceptably short period of time, or else needs to take on the job of periodically polling the pin itself. Large compute tasks should have polls sprinkled into them, or be broken into subtasks that can be run by a state machine in the main loop. Long delays should be rewritten in the form</p>

<pre><code>start = micros();
while (micros() - start &lt; howLong) {
  // poll the ADXL interrupt
}
</code></pre>

<p>or, again, avoided entirely by queuing up work for the main loop to run later, instead of calling <code>delay</code>.</p>

<p>Second, consider using direct port access for the polling. A check like <code>if (PORTB &amp; (1&lt;&lt;3))</code> compiles down to a bare couple of instructions, and costs 2 cycles if the interrupt isn't actually asserted (which will be the usual case). Doing <code>if (digitalRead(port))</code> does a call to a function which takes around 25 times as long. It's still only a few microseconds, but if you've taken the advice of the previous step to poll as frequently as possible to minimize latency, then you don't want all of those microseconds to add up and impact the performance of other code.</p>

<p>Lastly, a technique that doesn't make a lot of sense for <em>this</em> scenario, but could be applicable if you were running on a system other than an AVR-based Arduino, or if you wanted to react to some interrupt <em>other</em> than a level-triggered pin interrupt: you have an ISR that doesn't do any real work, but instead sets a global <code>volatile</code> variable to true and then immediately returns. Then in your main code, instead of polling the port directly, you check the value of that variable. If it's true, you set it to false and then run your "interrupt handler" code. The handler runs shortly after the interrupt triggers, but it's run in an interrupts-on context where it's safe to do slower operations or operations that require timer interrupts to work. This is equivalent to the old Linux concept of "bottom halves".</p>
 4143: <p>Just because a pin is called "interrupt" doesn't mean that you have to read it using an interrupt input.  The INTx pins of the ADXL345 are simple "level" outputs.  All the time there is an "interrupt" pending (a signal from the ADXL345 that something has happened) the corresponding INT pin is held LOW.  It remains LOW until the interrupt has been handled by your code.</p>

<p>It's not something that is very brief - it's something that persists as long as you need it to.</p>

<p>You can just read the INTx pins with normal <code>digitalRead()</code> from within your <code>loop()</code> function (polling). Unless you <em>really</em> need to respond <em>right now</em> to an event on the ADXL345 there is no need to use an interrupt input. </p>
