Skip to content

Conversation

kaspar030
Copy link
Contributor

  • re-use a thread's "rq_entry" for mutex queue
  • re-use mutex queue to indicate a locked mutex
  • don't use atomic variable for mutex
  • unify mutex_lock and mutex_trylock

(The last three were adopted from @Kijewski's #4555)

@kaspar030 kaspar030 added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Area: core Area: RIOT kernel. Handle PRs marked with this with care! labels Dec 29, 2015
@kaspar030
Copy link
Contributor Author

Result is 4% more speed, 20 bytes code saved and sizeof(mutex) == sizeof(void*).


#define ENABLE_DEBUG (0)
#include "debug.h"

static void mutex_wait(struct mutex_t *mutex);
#define MUTEX_LOCKED ((void*)0xFFFFFFFF)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(this needs 16bit adjustments)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just use -1 instead of 0xFF…FF.

@Kijewski
Copy link
Contributor

Re-usuing tcb_t::rq_entry makes sense. I did not look into the diff properly, yet.

@kaspar030
Copy link
Contributor Author

One advantage of reusing "rq_entry" is that mutexes don't need any space in tcb_t anymore. Before, they shared "wait_data" with msg.

@kaspar030
Copy link
Contributor Author

found another ~2.5%

@kaspar030 kaspar030 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet labels Jan 26, 2016
@jnohlgard
Copy link
Member

needs rebase

@kaspar030 kaspar030 force-pushed the introduce_intrusive_singly_linked_list branch from 351a2fe to c4e3849 Compare February 8, 2016 14:01
@kaspar030
Copy link
Contributor Author

  • rebased

@jnohlgard
Copy link
Member

Could you make a short summary of the benefits of the new linked list implementation?
There's already core/include/clist.h and sys/include/utlist.h.

The casts from list_node_t* to clist_node_t* to get the tcb_t looks a bit hairy to me and I would expect them to possibly break in unexpected creative ways on some changes to the clist implementation.

list_node_t *new_node = (list_node_t*)&thread->rq_entry;
new_node->next = NULL;

while (list->next) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will exit on next == MUTEX_LOCKED.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't _mutex_lock() catch that case before calling thread_add_to_list()?

@OlegHahm OlegHahm added the CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable label Feb 8, 2016
@kaspar030
Copy link
Contributor Author

Could you make a short summary of the benefits of the new linked list implementation?
There's already core/include/clist.h and sys/include/utlist.h.

The main difference to clist is that clist is doubly-linked and circular, while the new list is only singly-linked and has two ends.
Both are designed to be intrusive.
The new list only needs one pointer per list object, so unless the rq_entry type becomes < sizeof(void*), the cast should be fine. I used rq_entry as a thread is either on a runqueue or in a mutex waiting list.

This way, mutex_t is only one-field-sized (a list entry).

(After a short list edit look into utlist.h, I decided a singly linked list is simple enough to re-implement. utlist.h would have never made it through our current coding best practices.)

@kaspar030
Copy link
Contributor Author

  • rebased

@OlegHahm OlegHahm mentioned this pull request Feb 28, 2016
1 task
* @param[in] node list node before new entry
* @param[in] new_node list node to insert
*/
static inline void list_add(list_node_t *node, list_node_t *new_node) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do

static inline void list_add(list_node_t **node, list_node_t *new_node) {
    if (*node == NULL) {
        *node = new_node;
    }
    else {
        new_node->next = node->next;
        node->next = new_node;
    }
}

To make the API more consistent with clist_node_t (empty list is NULL).

edit: fixed dereferencialization in if statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow I dislike replacing two lines with four for API consistency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then how is an empty list represented in your version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As pointer to the first element. edit misread.

A list is represented as pointer to the first element, and that struct is conveniently the same as that of a list node. So if the list is empty, the list node representing the list has a NULL next ptr.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you always need one extra element in memory? That's not ideal either ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay. I did not read it that way. So an empty list is still a NULL pointer in your version? Wouldn't this just require the user to add the check I introduced above anyways i.e. just put the code outside the API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, every list is a "list_node_t". That struct just happens to only contain a pointer. If there are elements, that pointer points to the first element, if not, it is NULL.
The add function inserts an element after another. If the root node of the list is specified as first parameter, the new object will be the new head of the list.
The remove_head function removes the first and returns it, if any.
No further checks needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is never called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have the time to understand the full PR, I'm just a bit confused why you introduce a new list implementation and use only the "remove head" function.

@kaspar030
Copy link
Contributor Author

The casts from list_node_t* to clist_node_t* to get the tcb_t looks a bit hairy to me and I would expect them to possibly break in unexpected creative ways on some changes to the clist implementation.

Could be solved by using a union...

@kaspar030 kaspar030 force-pushed the introduce_intrusive_singly_linked_list branch from 4cc6e0e to 3cbcf3c Compare March 21, 2016 10:56
@OlegHahm
Copy link
Member

Needs a rebase.

@kaspar030 kaspar030 force-pushed the introduce_intrusive_singly_linked_list branch from 3cbcf3c to 0b5ea41 Compare March 23, 2016 23:05
@kaspar030
Copy link
Contributor Author

  • rebased

*/

#ifndef __LIST_H
#define __LIST_H
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought these underscores were forbidden?

@kaspar030 kaspar030 force-pushed the introduce_intrusive_singly_linked_list branch from 0b5ea41 to a93196c Compare March 29, 2016 18:08
list = list->next;
}

list->next = new_node;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't you use list_add() here, so you don't break the list? So if the current list->next is somewhere in the middle of the list, and we run the line above, the items that have been pointed to by list->next before are dropped from the list, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ups, overlooked l119, so everything should be ok. You might want to more l119 out of the loop and remove l114 though.

@kaspar030 kaspar030 removed the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Mar 29, 2016
@kaspar030
Copy link
Contributor Author

  • addressed comments

@haukepetersen
Copy link
Contributor

Code looks good, tested with #5190 and mutex_unlock_and_sleep on native and on some ARM boards. ACK

@kaspar030 kaspar030 force-pushed the introduce_intrusive_singly_linked_list branch from f60ec99 to 3d9020e Compare March 29, 2016 19:50
@kaspar030
Copy link
Contributor Author

  • squashed

@kaspar030 kaspar030 added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Mar 29, 2016
* the container_of() macro in list operations.
* See @ref thread_add_to_list() as example.
*/
typedef struct list_node {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want the struct name here, or am I missing something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I missed the next line. sorry (:

@cgundogan
Copy link
Member

code looks good. ACK

@kaspar030
Copy link
Contributor Author

And go. Thanks for reviewing!

@kaspar030 kaspar030 merged commit f626ee5 into RIOT-OS:master Mar 29, 2016
@kaspar030 kaspar030 deleted the introduce_intrusive_singly_linked_list branch March 29, 2016 20:25
@kaspar030 kaspar030 restored the introduce_intrusive_singly_linked_list branch March 29, 2016 22:22
@jnohlgard jnohlgard mentioned this pull request Jul 17, 2016
@kaspar030 kaspar030 deleted the introduce_intrusive_singly_linked_list branch February 7, 2017 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: core Area: RIOT kernel. Handle PRs marked with this with care! CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants