Multiple queueing and working queues - linux-kernel

I'm learning the Work queues to code bottom halves in the linux kernel.
I wonder: if the interrupt handler is executed two times (thus calling schedule_work two times), does the work queue handler be called once or twice?

Looks like your answer is in the comment for the function.
/**
* schedule_work - put work task in global workqueue
* #work: job to be done
*
* Returns zero if #work was already on the kernel-global workqueue and
* non-zero otherwise.
*
* This puts a job in the kernel-global workqueue if it was not already
* queued and leaves it in the same position on the kernel-global
* workqueue otherwise.
*/
int schedule_work(struct work_struct *work)
{
return queue_work(keventd_wq, work);
}

Related

SetAccessor and SetAccessorProperty, any difference?

V8's ObjectTemplate provides us two ways to attach a so-called accessor property to the object under instantiation.
The first one is ObjectTemplate::SetAccessor:
/**
* Sets an accessor on the object template.
*
* Whenever the property with the given name is accessed on objects
* created from this ObjectTemplate the getter and setter callbacks
* are called instead of getting and setting the property directly
* on the JavaScript object.
*
* \param name The name of the property for which an accessor is added.
* \param getter The callback to invoke when getting the property.
* \param setter The callback to invoke when setting the property.
* \param data A piece of data that will be passed to the getter and setter
* callbacks whenever they are invoked.
* \param settings Access control settings for the accessor. This is a bit
* field consisting of one of more of
* DEFAULT = 0, ALL_CAN_READ = 1, or ALL_CAN_WRITE = 2.
* The default is to not allow cross-context access.
* ALL_CAN_READ means that all cross-context reads are allowed.
* ALL_CAN_WRITE means that all cross-context writes are allowed.
* The combination ALL_CAN_READ | ALL_CAN_WRITE can be used to allow all
* cross-context access.
* \param attribute The attributes of the property for which an accessor
* is added.
* \param signature The signature describes valid receivers for the accessor
* and is used to perform implicit instance checks against them. If the
* receiver is incompatible (i.e. is not an instance of the constructor as
* defined by FunctionTemplate::HasInstance()), an implicit TypeError is
* thrown and no callback is invoked.
*/
void SetAccessor(
Local<String> name, AccessorGetterCallback getter,
AccessorSetterCallback setter = nullptr,
Local<Value> data = Local<Value>(), AccessControl settings = DEFAULT, // note the data is on the template level.
PropertyAttribute attribute = None, // not on the instance level.
Local<AccessorSignature> signature = Local<AccessorSignature>(),
SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);
and the second one is Template::SetAccessorProperty:
void SetAccessorProperty(
Local<Name> name, // The latter one is called data property.
Local<FunctionTemplate> getter = Local<FunctionTemplate>(),
Local<FunctionTemplate> setter = Local<FunctionTemplate>(),
PropertyAttribute attribute = None,
AccessControl settings = DEFAULT);
Having two very similar APIs confuses me a lot.
Unfortunately there is no docs describing their differences, so I have to do experiment on my own. I found that the combination of Holder() and SetAccessor() will break, while other combinations of Holder() or This() and SetAccessor() or SetAccessorProperty() work fine. On a previous post I ran into this failing combination and was fooled to believe what's went wrong is Holder() or This(). But after the experiment I now believe that it is SetAccessor went wrong.
My question is, whether SetAccessor is a deprecated API? If so, all we have to do is stop using it. If not so, please explain a little bit their differences, esspecially in causing this failure. Many thanks to the warm-hearted and experienced V8 developers!
I agree that the names can be a bit confusing; neither is deprecated. The difference is as follows:
SetAccessor creates a "magic" data property: it looks like a data property to JavaScript (getOwnPropertyDescriptor returns {value: ..., ...}), but when reading/writing the property, the C++ callbacks you specified will be called. For a built-in example, think of Array.prototype.length (where in particular the setter has to do additional work when you use a .length assignment to shorten an array).
SetAccessorProperty creates a regular accessor property, i.e. getOwnPropertyDescriptor returns {get: ..., set: ..., ...}. A built-in example would be Int32Array.prototype.__proto__.byteLength. The name "SetAccessorProperty" reflects the fact that the JS spec calls these properties "accessor properties".
Chances are that in many cases, this difference doesn't matter: interfacing JavaScript code can read and/or write properties either way. But sometimes you might have a reason to care about the distinction, and in that case V8's API gives you that flexibility.

mapping a memory region from kernel

I have a register which needs to be accessed from more then one driver.
It is a global read-only register resides in FPGA space
The register address is exported via device tree.
The first call to "request_mem_region" is ok, but any consecutive call fails.
Is there a way to share a register between drivers ?
Linux Kernel release is 4.14 , using petalinux
Thanks,
Ran
You need to remap the memory region with something like ioremap() after you have requested it.
Then, as Tsyvarev and others mentioned, create and export a function in your "parent" driver that returns the mapped memory.
Here is some rough code:
void * mapped_mem;
void * map_addr(unsigned int phy_addr, char * name) {
struct resource * resource;
void * mapped_mem;
resource = request_mem_region(phy_addr, page_size * 4, name);
// check for errors
mapped_mem= ioremap_nocache(phy_addr, page_size * 4);
// check for errors
return mappedMem;
//handle errors
}
void * get_mapped_addr(void) {
return mapped_mem
}
EXPORT_SYMBOL( get_mapped_addr);
Now, mapped_mem should actually be tracked as part of your devices private info, but I figure thats beyond the scope of the question. Also, make sure to check for all possible errors. Make sure that request_mem_region() returns something >0 and not Null.

How to obtain an InputStream when opening an IgnitePath (returns HadoopIgfsSecondaryFileSystemPositionedReadable)?

Usually, when working with Hadoop and Flink, opening/reading a file from a distributed file system will return a Source (counterpart of Sink) object extending the java.io.InputStream.
However, in Apache Ignite, the IgfsSecondaryFileSystem, and more specifically the IgniteHadoopIgfsSecondaryFileSystem, returns an object of type HadoopIgfsSecondaryFileSystemPositionedReadable when calling their "open" method (by passing an IgfsPath).
HadoopIgfsSecondaryFileSystemPositionedReadable offers a "read" method but requires to know details on where the data, which is intended to be read, is located, such as the input stream position.
/**
* Read up to the specified number of bytes, from a given position within a file, and return the number of bytes
* read.
*
* #param pos Position in the input stream to seek.
* #param buf Buffer into which data is read.
* #param off Offset in the buffer from which stream data should be written.
* #param len The number of bytes to read.
* #return Total number of bytes read into the buffer, or -1 if there is no more data (EOF).
* #throws IOException In case of any exception.
*/
public int read(long pos, byte[] buf, int off, int len) throws IOException;
How to determine these details before calling the read method?
I am quite new to these frameworks and maybe there exists a different way to obtain an InputStream based on an IgfsPath pointing to a file stored in a Hadoop file system?
I am trying to achieve what is described here: https://apacheignite-fs.readme.io/docs/secondary-file-system
Thanks in advance for any hint !
IgfsSecondaryFileSystem interface is not supposed to be used directly. You can configure your Hadoop cluster to be used as a secondary FS for read-through and write-through operations.
IgfsSecondaryFileSystem should only be specified in configuration as FileSystemConfiguration#secondaryFileSystem property.
You should use IgniteFileSystem interface instead. You can get an instance of it by calling Ignite#fileSystem(...) method. To acquire an InputStream by IGFS path, you can use IgniteFileSystem#open(...) method.

Execution context in Event driven programming

I am reading about event driven programming from the book:
Practical UML Statecharts in C/C++, 2nd Edition:
Event-Driven Programming for Embedded Systems
On page no. xxviii Introduction , the author says:
...the event-driven application must return control after handling
each event, so the execution context cannot be preserved in the
stack-based variables and the program counter as it is in a sequential
program. Instead, the event-driven application becomes a state
machine, or actually a set of collaborating state machines that
preserve the context from one event to the next in the static
variables.
I am unable to understand why the execution context cannot be preserved in the stack-based variables and the program counter once the control is returned after handling the event?
Let's start with how the traditional sequential programming paradigm works. Suppose that you want to blink an LED on an embedded board. A common solution would be to write a program like this (e.g., see Arduino Blink tutorial):
while (1) { /* RTOS task or a "superloop" */
turn_LED_on(); /* turn the LED on (computation) */
delay(500); /* wait for 500 ms (polling or blocking) */
turn_LED_off(); /* turn the LED off (computation) */
delay(1000); /* wait for 1000 ms (polling or blocking) */
}
The key point here is the delay() function, which waits in-line until the delay elapses. This waiting is called "blocking", because the calling program is blocked until delay() returns.
Please note that the Blinky program calls delay() in two different contexts: first time after turn_LED_on() and the second time after turn_LED_off(). Each time, delay() returns to a different place in the code. This means that while the program is blocked, the information about the place in the code (the context of the call) is automatically preserved.
The trivial Blinky program is very simple, but in principle a blocking function, like delay(), could be called from other functions each with
complex if-else-while code. Still, delay() will be able to return to the exact point of the call, because the C programming language preserves the context of the call (in the call stack and the program counter).
But blocking makes the whole program unresponsive to any other events and therefore people came up with event-driven programming.
An event-driven program is structured around an event-loop. An example event-driven code could look like this:
while (1) { /* event-loop */
Event *e = queue_get(); /* block when event queue is empty */
dispatch(e); /* handle the event, cannot block! */
}
The main point is that the dispatch() "event-handler" function cannot call a blocking function like delay(). Instead, dispatch() can only perform some immediate action and must quickly return back to the event-loop. That way, the event-loop remains responsive at all times.
But, by returning the dispatch() function removes its own stack frame from the call stack. So the call stack and program counter associated with calling dispatch() is always the same and is useless to "remember" the execution context.
Instead, to blink the LED, the dispatch() function must rely on some variable (state) that remembers the state (on/off) of the LED. An example how you could write such dispatch() function is as follows:
static enum {OFF, ON } state = OFF; /* start in the OFF state */
timer_arm(1000); /* arm a timer to generate TIMEOUT event in 1000 ms */
void dispatch(Event *e) {
switch (state) {
case OFF:
if (e->sig == TIMEOUT) {
turn_LED_on();
timer_arm(500);
state = ON; /* transition to "ON" state */
}
break;
case ON:
if (e->sig == TIMEOUT) {
turn_LED_off();
timer_arm(1000);
state = OFF; /* transition to "OFF" state */
}
break;
}
}
I hope you can see that dispatch() implements a state machine with states ON and OFF driven by one event TIMEOUT.

Lossless rate-limiting in RxJS with queue clearing

In rxjs5, I'm trying to implement a Throttler class.
import Rx from 'rxjs/rx';
export default class Throttler {
constructor(interval) {
this.timeouts = [];
this.incomingActions = new Rx.Subject();
this.incomingActions
.concatMap(action => Rx.Observable.just(action).delay(interval / 2))
.subscribe(action => action());
}
clear() {
// How do I do this?
}
do(action) {
this.incomingActions.next(action);
}
}
The following invariants must hold:
every action passed to do gets added to an action queue
the action queue gets processed in order and at a fixed interval as determined by the constructor parameter
the action queue can be cleared using clear().
My current implementation, as seen above, handles the fixed interval, but I don't know how to clear the queue. It also has the problem that all actions are delayed by interval / 2ms even when the queue is empty.
P.S. The way I describe the invariants maps very easily to an implementation with setInterval and an array as a queue, but I'm wondering how I would do this with Rx.
This seems like not a good place for the default Subject class. Extending it with your own subclass would be better because of reasons you listed.
However, in your case I'd try to identify each action that comes to .do(action) method with some index and add .filter() operator before subscribe() to be able to cancel particular actions by checking some array for what indices are marked as canceled. Since you're using concatMap() you know that actions will be always called in the order they were added. Then clear() method that you want would just mark all actions to be canceled in the array.
You can also add .do() operator after concatMap() and keep track of how many action are scheduled at the moment with some accumulator. Adding action would cause scheduledAction++ while passing .do() right before .subscribe() would scheduledAction--. Then you can use this variable to decide whether you want to chain a new action with .delay(interval / 2) or not.

Resources