In the practical application, a task often needs to wait for multiple semaphores to take effect at the same time, or the task needs to determine the operation mode of the task according to the result of the combination of multiple semaphores, in order to realize the function of the multi-signal combination, Ucos realizes the special structure of the signal volume set.
The basis of the semaphore set is still the semaphore, which is like a plurality of semaphores consisting of a non-gate to form the execution of a logical result control task.
The signal volume in the implementation of the Ucos is divided into two parts, the first part is called the Flag group, which holds all signals in the signal concentration, the second is called the waiting list, each node in the list corresponds to a waiting task waiting for the semaphore set, the semaphore set according to the list to manage the waiting task
Unlike events such as Message Queuing message mailboxes, Ucos defines a semaphore set using a new structure called a flag group, which is structured as follows
typedef struct OS_FLAG_GRP {/* Event flag Group */
Int8u Osflagtype; /* semaphore set flag, must be Os_event_type_flag */
void *osflagwaitlist; /* Pointer to the first node of the task waiting group */
Os_flags Osflagflags; /* The length of the semaphore set */
#if os_flag_name_en > 0u
Int8u *osflagname;
#endif
} os_flag_grp;
The first few have comments, note osflagflags, which is a variable of type os_flags, in Osflagflags, a bit represents a semaphore, how much semaphore a flag group can hold depends on the length of the Os_flags, and Os_ The length definition of flags can make 8 bits of 16 bits 32 bits, as follows
#if Os_flags_nbits = = 8u
typedef int8u OS_FLAGS;
#endif
#if Os_flags_nbits = = 16u
typedef int16u OS_FLAGS;
#endif
#if Os_flags_nbits = = 32u
typedef INT32U OS_FLAGS;
#endif
Macros that determine their length are specified in the Os_cfg.h file, typically 16 bits, and are determined as needed
Osflagwaitlist points to a pointer to the list of tasks waiting for this semaphore set, and after the creation of a semaphore set is not directly connected to the task, then again, let's look at how the system manages the semaphore set
In fact, the management of the semaphore set is similar to the previous TCB ECB and QCB management, which is the form of the idle list, which has an array of flags in the system, as follows
Os_ext Os_flag_grp Osflagtbl[os_max_flags];
This variable indicates the size of the maximum number of flag groups The system contains, Os_max_flags is the macro defined in the Os_cfg.h file, and the user configures it as needed
You can see the following code when the flag group is initialized
for (ix = 0u; IX < (OS_MAX_FLAGS-1U); ix++) {/* Init. List of free EVENT FLAGS */
Ix_next = IX + 1u;
PGRP1 = &OSFlagTbl[ix];
PGRP2 = &OSFlagTbl[ix_next];
Pgrp1->osflagtype = os_event_type_unused;
Pgrp1->osflagwaitlist = (void *) Pgrp2;
#if os_flag_name_en > 0u
Pgrp1->osflagname = (int8u *) (void *) "?"; /* Unknown Name */
#endif
}
PGRP1 = &OSFlagTbl[ix];
Pgrp1->osflagtype = os_event_type_unused;
Pgrp1->osflagwaitlist = (void *) 0;
#if os_flag_name_en > 0u
Pgrp1->osflagname = (int8u *) (void *) "?"; /* Unknown Name */
#endif
Osflagfreelist = &OSFlagTbl[0];
It can be clearly seen that the management of the semaphore set is similar to TCBQCB, which is managed using a linked list, with a osflagfreelist pointing to a flag group as the table header of the free flag group at initialization time. Osflagwaitlist joins each flag group variable as a list when no flag group is created
Osflagwaitlist is defined as follows
Os_ext Os_flag_grp *osflagfreelist;
This is the organization of the flag group, so how to associate the flag group with the semaphore set, relying on the function of Os_flagblock, the prototype is as follows
static void Os_flagblock (Os_flag_grp *pgrp,
Os_flag_node *pnode,
Os_flags FLAGS,
Int8u Wait_type,
int32u Timeout)
The first parameter is the set of flags we generate, the second is a pnode variable, flags is the semaphore set data for the specified wait, the fourth is the wait type, and finally the Wait timeout event
Pick a simple first say, wait time without repeating, the front has been carefully analyzed, said the waiting type, the waiting type of the flag group is divided into eight, respectively, as follows
#define Os_flag_wait_clr_all 0u//signal all valid to continue to perform the task
#define Os_flag_wait_clr_and 0u//But signal valid identification is 0 valid
#define OS_FLAG_WAIT_CLR_ANY 1u//signal has one or more valid
#define OS_FLAG_WAIT_CLR_OR 1u//But signal valid identification is 0 valid
#define Os_flag_wait_set_all 2u//signal all valid to continue to perform the task
#define Os_flag_wait_set_and 2u//Signal valid identification is 1 valid
#define OS_FLAG_WAIT_SET_ANY 3u//signal has one or more valid
#define OS_FLAG_WAIT_SET_OR 3u//Signal valid identification is 1 valid
For example, if Osflagflags is 0b00000000 at this point, the task set to Os_flag_wait_clr_all is valid, and the signal set to Os_flag_wait_set_all is not valid because the signal bit is 0. All is 0, so valid, the signal bit is 1 when the time is valid, no bit is 1, so invalid.
There is also a os_flag_node element, which is defined as follows
typedef struct OS_FLAG_NODE {
void *osflagnodenext; /* point to the next node node */
void *osflagnodeprev; /* point to the previous node */
void *OSFLAGNODETCB; /* tcb*/pointing to the current task node
void *osflagnodeflaggrp;
Os_flags Osflagnodeflags;
Int8u Osflagnodewaittype; /* Current WAIT type */
} Os_flag_node;
The member Osflagnodeflaggrp is a pointer to the semaphore set Flag group, which is used when waiting for a member to be deleted in the task list or when adding a member.
The osflagnodeflags is equivalent to a filter that can filter out the semaphore required by the request task from the flag group, and the rest of the extraneous signals are screened out,
The interface for establishing the connection between the node and the flag group is Os_flagblock, and the core code is as follows
Ostcbcur->ostcbstat |= Os_stat_flag;
Ostcbcur->ostcbstatpend = OS_STAT_PEND_OK;
ostcbcur->ostcbdly = timeout; /* Store timeout in task s TCB */
#if os_task_del_en > 0u
Ostcbcur->ostcbflagnode = Pnode; /* TCB to link to node */
#endif
Pnode->osflagnodeflags = flags; /* Save The flags that we need to wait for */
Pnode->osflagnodewaittype = Wait_type; /* Save The type of wait we are doing */
PNODE->OSFLAGNODETCB = (void *) ostcbcur; /* Link to Task s TCB */
Pnode->osflagnodenext = pgrp->osflagwaitlist; /* ADD node at beginning of event flag wait list */
Pnode->osflagnodeprev = (void *) 0;
PNODE->OSFLAGNODEFLAGGRP = (void *) pgrp; /* Link to Event Flag Group */
Pnode_next = (Os_flag_node *) pgrp->osflagwaitlist;
if (Pnode_next! = (void *) 0) {/* is this, the first NODE to insert? */
Pnode_next->osflagnodeprev = Pnode; /* No, link in doubly linked list */
}
Pgrp->osflagwaitlist = (void *) Pnode;
y = ostcbcur->ostcby; /* Suspend current task until flag (s) received */
Osrdytbl[y] &= (Os_prio) ~ostcbcur->ostcbbitx;
if (osrdytbl[y] = = 0x00u) {
Osrdygrp &= (Os_prio) ~ostcbcur->ostcbbity;
As you can see, he will hang the task first and then
Pnode->osflagnodenext = pgrp->osflagwaitlist;
Put the task in the Wait task list and finally switch the head of the task list to the node we just inserted, as follows
Pgrp->osflagwaitlist = (void *) Pnode;
In this way, the task is associated with the semaphore set, in the scheduling we can say that should be in the postxxx inside the dispatch, see after the following code found
Sched = Os_false; /* Indicate that we don ' t need rescheduling */
Pnode = (Os_flag_node *) pgrp->osflagwaitlist;
while (Pnode! = (Os_flag_node *) 0) {
.........
Pnode = (Os_flag_node *) pnode->osflagnodenext;
}
if (sched = = os_true) {
Os_sched ();
}
In other words, when another task sends a semaphore set, a wait-list traversal will occur inside the semaphore set, the appropriate task can be scheduled, and then call Os_sched to dispatch, thus realizing the semaphore set
Speaking of which, basically the principle of the semaphore set is almost the same thing, now talk about using
Create a semaphore set
Osflagcreate, returns a pointer to the semaphore set created
Request Semaphore Set
Osflagpend
Send a signal to a semaphore set
Osflagpost
Querying the state of the semaphore set
Osflagquery
Delete a semaphore set
Osflagdel
Adding tasks to a semaphore set (this is important)
Os_flagblock, this function has a os_flag_node parameter, in the generation of this variable, only need to assign value waittype and flags two, the rest of the interface will be automatically assigned, do not need the user or to manually assign value, remember
Source code Analysis of Ucos signal set