Peterson's solution: why does it not work in non preemptive scheduling sometimes? - mutual-exclusion

Why doesn't Peterson’s solution to the mutual-exclusion problem work when process scheduling is non-pre-emptive sometimes?
Can someone please help me understand in the context of peterson's solution?
Thank you for your time and help!
Peterson's solution:
#define FALSE 0 /* number of processes */
#define TRUE 1
#define N 2
int turn; /* who's turn is it? */
int interested[N];
void enter_region(int process);
{
int other;
other = 1 - process; /* the opposite of process*/
interested[process] = TRUE; /* show that you are interested*/
turn = process; /* set flag */
while (turn == process && interested[other] == TRUE) /* null statement */
}
void leave_region(int process) /* process: who is leaving */
{
interested[process] = FALSE; /* indicate departure from critical region*/
}

Related

STM32L496 - FLASH Page Erase No Effect

I have a project originally built for the STM32L432 that I am porting to the STM32L496. However, I am having an issue where the HAL_FLASHEx_Erase function provided by ST as part of the HAL works on one device but not the other. The two FLASH spaces of these micros are organized virtually identically (same 72-bit wide data read/writes). Only difference is the L496 has a second bank of FLASH. I have seen some users run into issues with this; I am NOT attempting to use Bank 2 or come anywhere close to it; my last address is at 0x801FFFF.
I can manually erase the FLASH using the STCube Programmer, which fills it with FFs. This then satisfies the requirement for the FLASH to be "erased" before writing, and I can write one block of data. But I cannot modify it again via code. As soon as I write the first time, I cannot clear the block of data that I'd just written (verified using the Memory window view in IAR).
Again, exact same piece of code works for one L-series, but not another. Anyone have any ideas?
HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)
{
HAL_StatusTypeDef status = HAL_ERROR;
uint32_t page_index = 0;
/* Process Locked */
__HAL_LOCK(&pFlash);
/* Check the parameters */
assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == HAL_OK)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
if (pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
{
/* Mass erase to be done */
FLASH_MassErase(pEraseInit->Banks);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
#if defined(STM32L471xx) || defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L485xx) || defined(STM32L486xx)
/* If the erase operation is completed, disable the MER1 and MER2 Bits */
CLEAR_BIT(FLASH->CR, (FLASH_CR_MER1 | FLASH_CR_MER2));
#else
/* If the erase operation is completed, disable the MER1 Bit */
CLEAR_BIT(FLASH->CR, (FLASH_CR_MER1));
#endif
}
else
{
/*Initialization of PageError variable*/
*PageError = 0xFFFFFFFF;
for(page_index = pEraseInit->Page; page_index < (pEraseInit->Page + pEraseInit->NbPages); page_index++)
{
FLASH_PageErase(page_index, pEraseInit->Banks);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the PER Bit */
CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB));
if (status != HAL_OK)
{
/* In case of error, stop erase procedure and return the faulty address */
*PageError = page_index;
break;
}
}
}
/* Flush the caches to be sure of the data consistency */
FLASH_FlushCaches();
}
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}

LPC824 microcontroller ADC demo HardFault problem

I'm trying to program LPC824 microcontroller board ([https://www.switch-science.com/catalog/2265/][1]) with LPCOpen.
I'm using it with LPCLink 2 debugger board.
My goal is to get some information from the "pressure sensor" with an ADC.
My code stops with a HardFault when executing a NVIC_EnableIRQ function(on line: 92).
If I don't use "NVIC interrupt controller" then my code works and I can get value from sensor with ADC.
What I am doing wrong?
Here is my adc.c code:
#include "board.h"
static volatile int ticks;
static bool sequenceComplete = false;
static bool thresholdCrossed = false;
#define TICKRATE_HZ (100) /* 100 ticks per second */
#define BOARD_ADC_CH 2
/**
* #brief Handle interrupt from ADC sequencer A
* #return Nothing
*/
void ADC_SEQA_IRQHandler(void) {
uint32_t pending;
/* Get pending interrupts */
pending = Chip_ADC_GetFlags(LPC_ADC);
/* Sequence A completion interrupt */
if (pending & ADC_FLAGS_SEQA_INT_MASK) {
sequenceComplete = true;
}
/* Threshold crossing interrupt on ADC input channel */
if (pending & ADC_FLAGS_THCMP_MASK(BOARD_ADC_CH)) {
thresholdCrossed = true;
}
/* Clear any pending interrupts */
Chip_ADC_ClearFlags(LPC_ADC, pending);
}
/**
* #brief Handle interrupt from SysTick timer
* #return Nothing
*/
void SysTick_Handler(void) {
static uint32_t count;
/* Every 1/2 second */
if (count++ == TICKRATE_HZ / 2) {
count = 0;
Chip_ADC_StartSequencer(LPC_ADC, ADC_SEQA_IDX);
}
}
/**
* #brief main routine for ADC example
* #return Function should not exit
*/
int main(void) {
uint32_t rawSample;
int j;
SystemCoreClockUpdate();
Board_Init();
/* Setup ADC for 12-bit mode and normal power */
Chip_ADC_Init(LPC_ADC, 0);
Chip_ADC_Init(LPC_ADC, ADC_CR_MODE10BIT);
/* Need to do a calibration after initialization and trim */
Chip_ADC_StartCalibration(LPC_ADC);
while (!(Chip_ADC_IsCalibrationDone(LPC_ADC))) {
}
/* Setup for maximum ADC clock rate using sycnchronous clocking */
Chip_ADC_SetClockRate(LPC_ADC, ADC_MAX_SAMPLE_RATE);
Chip_ADC_SetupSequencer(LPC_ADC, ADC_SEQA_IDX,
(ADC_SEQ_CTRL_CHANSEL(BOARD_ADC_CH) | ADC_SEQ_CTRL_MODE_EOS));
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
Chip_SWM_EnableFixedPin(SWM_FIXED_ADC2);
Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM);
/* Setup threshold 0 low and high values to about 25% and 75% of max */
Chip_ADC_SetThrLowValue(LPC_ADC, 0, ((1 * 0xFFF) / 4));
Chip_ADC_SetThrHighValue(LPC_ADC, 0, ((3 * 0xFFF) / 4));
Chip_ADC_ClearFlags(LPC_ADC, Chip_ADC_GetFlags(LPC_ADC));
Chip_ADC_EnableInt(LPC_ADC,
(ADC_INTEN_SEQA_ENABLE | ADC_INTEN_OVRRUN_ENABLE));
Chip_ADC_SelectTH0Channels(LPC_ADC, ADC_THRSEL_CHAN_SEL_THR1(BOARD_ADC_CH));
Chip_ADC_SetThresholdInt(LPC_ADC, BOARD_ADC_CH, ADC_INTEN_THCMP_CROSSING);
/* Enable ADC NVIC interrupt */
NVIC_EnableIRQ(ADC_SEQA_IRQn);
Chip_ADC_EnableSequencer(LPC_ADC, ADC_SEQA_IDX);
SysTick_Config(SystemCoreClock / TICKRATE_HZ);
/* Endless loop */
while (1) {
/* Sleep until something happens */
__WFI();
if (thresholdCrossed) {
thresholdCrossed = false;
printf("********ADC threshold event********\r\n");
}
/* Is a conversion sequence complete? */
if (sequenceComplete) {
sequenceComplete = false;
/* Get raw sample data for channels 0-11 */
for (j = 0; j < 12; j++) {
rawSample = Chip_ADC_GetDataReg(LPC_ADC, j);
/* Show some ADC data */
if (rawSample & (ADC_DR_OVERRUN | ADC_SEQ_GDAT_DATAVALID)) {
printf("Chan: %d Val: %d\r\n", j, ADC_DR_RESULT(rawSample));
printf("Threshold range: 0x%x ",
ADC_DR_THCMPRANGE(rawSample));
printf("Threshold cross: 0x%x\r\n",
ADC_DR_THCMPCROSS(rawSample));
printf("Overrun: %s ",
(rawSample & ADC_DR_OVERRUN) ? "true" : "false");
printf("Data Valid: %s\r\n\r\n",
(rawSample & ADC_SEQ_GDAT_DATAVALID) ?
"true" : "false");
}
}
}
}
}
Hard fault usually means that you try to execute code outside allowed addresses. If you have not registered the interrupt in the vector table but enabled it, the MCU will jump to whatever address that's written there instead, after which the program crashes.
How to fix that depends on tool chain. Assuming LPCXpresso, you have several options to set up libraries (I don't know about LPCOpen specifically), so where to find the vector table is different from case to case. However, this works quite similar on most MCUs, ARM or not. Somewhere in a "crt start-up" file you should have something along the lines of this:
void (* const g_pfnVectors[])(void) = ...
This is an array of function pointers which will be the vector table allocated in memory at address 0 on Cortex M. You have to place your function at the relevant interrupt vector. For example it may say something like
PIN_INT0_IRQHandler, // PIO INT0
If that's the interrupt you should implement, then you replace that line:
#include "my_irq_stuff.h"
...
void (* const g_pfnVectors[])(void) =
...
my_INT0, // PIO INT0
Assuming my_irq_stuff.h contains the function prototype my_INT0 for the interrupt service routine. The actual routine should be implemented in the corresponding .c file.

STM32F4 UART Rx Interrupt Example Code

I've been trying to implement a basic per-byte UART Rx Interrupt on a STM32F4 board using HAL skeleton code generated by STMCubeMX version 4.26.0
Quite simply - I want to receive a character in UART1 via an Rx interrupt and transmit it on UART 6
I have successfully implemented a polled version of what I want to achieve
uint8_t in_usart1[10];
HAL_StatusTypeDef usart1_status;
usart1_status = HAL_UART_Receive(&huart1, in_usart1, 1, 1);
if (usart1_status != HAL_TIMEOUT)
{
HAL_UART_Transmit(&huart6, in_usart1, 1, 100);
}
I've enabled the UART 1 NVIC interrupt in STMCubeMX and stm32f4xx_it.c contains the IRQ handler which I've added my own user handler to:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
HAX_USART1_IRQHandler(&huart1); /* My Handler */
/* USER CODE END USART1_IRQn 1 */
}
I've seen lot's of commentary about UART_Receive_IT() - but I suspect this is based on older versions of HAL due to UART_Receive_IT() being defined in stm32f4xx_hal_uart.c
My suspicion is that I need to enable to interrupt / clear the interrupt flag as when I debug, USART1_IRQHandler() is NEVER called
Does any one have any code that demonstrates what I am trying to achieve? My google-foo has failed me
EDIT:
I've gotten a little closer... In main.c I added (comments are existing code)
/* USER CODE BEGIN PV */
uint8_t rx_buffer;
/* USER CODE END PV */
...
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_buffer, 10);
/* USER CODE END 2 */
And then created:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
HAL_UART_Transmit(&huart6, &rx_buffer, 1, 100);
}
}
Now the Rx interrupt gets fired - but it's a bit flakey on the USART6 Tx, and the Rx interrupt only gets fired once
Do not block HAL_UART_RxCpltCallback for a long time! Just set a flag and check it and then send data from the main function.
And rx_buffer is variable so correct call HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);
For anybody stumbling across this question, the answer is embarrassingly simple. I have two UARTs - One I was using an Rx Interrupt, and the other using DMA.
Turns out the one I thought I had configured for Interrupt was actually configured for DMA and visa-versa...
In STMCubeMX
- USART1 (RS485) has DMA Tx and DMA Rx enabled
- USART6 (Debug - RS232) has global interrupt enabled
In main.c
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
/* USER CODE END 2 */
I have a user_main.c which has the following code:
#include <string.h>
#include "stm32f4xx_hal.h"
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart6;
UART_HandleTypeDef *debug_uart(void)
{
return &huart6;
}
UART_HandleTypeDef *rs485_uart(void)
{
return &huart1;
}
#define BUFFER_SIZE 1
uint8_t debug_rx_buffer[BUFFER_SIZE];
uint8_t debug_tx_buffer[BUFFER_SIZE];
uint8_t rs485_rx_buffer[BUFFER_SIZE];
uint8_t rs485_tx_buffer[BUFFER_SIZE];
static void rs485_tx(uint8_t *tx_buffer, uint16_t len)
{
HAL_UART_Transmit_DMA(rs485_uart(), tx_buffer, len);
}
static void debug_tx(uint8_t *tx_buffer, uint16_t len)
{
HAL_UART_Transmit(debug_uart(), tx_buffer, len, 1000);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == debug_uart())
{
memcpy(rs485_tx_buffer, debug_rx_buffer, BUFFER_SIZE);
rs485_tx(rs485_tx_buffer, BUFFER_SIZE);
HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
}
else if (huart == rs485_uart())
{
memcpy(debug_tx_buffer, rs485_rx_buffer, BUFFER_SIZE);
debug_tx(debug_tx_buffer, BUFFER_SIZE);
HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == debug_uart())
{
}
else if (huart == rs485_uart())
{
}
}
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
}
The memcpy()'s may not be strictly required, but they do provide a level of isolation between all the buffers. Technically, there probably should be semaphores providing even more protection...
Note that I DO NOT use HAL_UART_Transmit_IT() for the debug UART - If you want to use HAL_UART_Transmit_IT (i.e. interrupt generated on completion of Tx), you will need to write code that handles transmission of characters from a circular buffer

Delayed uart command execution

I'm writing a small embedded program, where I send some commands over uart to the atmega328p chip. The commands start with the character $ and end with the character # (so I know when to perform the parsing). Upon receiving the command I parse it and turn the device on (COMMAND:TURN_ON_I1) or off (COMMAND:TURN_OFF_I1). The application currently looks like this:
// ------- Defines -------- //
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>
#include <stdio.h>
#include <string.h>
#include "pinDefines.h"
#include "USART.h"
#define RECEIVE_BUFFER_SIZE 100
// Control output value
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
// Set pin mode (input or output)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
// The DDRD port contains only two pins:
#define REL_BTN_SIM_2 PD6 // PD6 = REL_BTN_SIM_2
void initUSART(void) { /* requires BAUD */
UBRR0H = UBRRH_VALUE; /* defined in setbaud.h */
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}
void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}
uint8_t receiveByte(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait for incoming data */
return UDR0; /* return register value */
}
void transmitByte(uint8_t data) {
/* Wait for empty transmit buffer */
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data; /* send data */
}
int main(void) {
//$COMMAND:TURN_ON_I1#
//$COMMAND:TURN_OFF_I1#
char s[RECEIVE_BUFFER_SIZE];
char readSerialCharacter;
// -------- Inits --------- //
DDRB = 0b00000111;
DDRC = 0b00001000;
DDRD = 0b11000000;
initUSART();
// ------ Event loop ------ //
while (1) {
printString("Waiting for the start of string (char $).\r\n");
do { } while ( receiveByte() != '$'); // Wait for start of string.
// Fill the array until the end of transmission is received
int i=0;
do {
// If nearing end of buffer, don't fill the buffer and exit the loop
if(i<RECEIVE_BUFFER_SIZE-1){
readSerialCharacter = receiveByte();
s[i++] = readSerialCharacter;
}else
break;
} while (readSerialCharacter != '#'); // Wait for end of string.
s[i] ='\0'; // Terminate the string
printString("The whole received command:\r\n");
printString(s);
printString("\r\n");
// Other commands (temperature, relay control)
// REL_BTN_SIM_2
else if(strstr(s, "COMMAND:TURN_ON_I1") != NULL)
{
printString("Will set I1 on!");
output_high(PORTD, REL_BTN_SIM_2);
}
else if(strstr(s, "COMMAND:TURN_OFF_I1") != NULL)
{
printString("Will set I1 off!");
output_low(PORTD, REL_BTN_SIM_2);
}
else
printString("Unknown command.\r\n");
// Clear the buffer
memset(s,'\0', sizeof(s));
}
/* End event loop */
return (0);
}
I noticed that after I send a command around seven or eight times (or more), the serial communication is interrupted or that the command is executed with a delay. I can also see, that the debug strings "Will set I1 off!", "Will set I1 on!" are printed, but the state of the outputs are not changed (or are changed with a delay of a couple of seconds).
I was wondering if someone would know, what I'm doing wrong?
Thanks.
You have a nice definition of set_output(), but you are not using it. So I suspect that you never enabled the output driver. By setting the port register, you just enable the weak pull-up. Maybe that is not strong enough to switch on your relay driver fast. Do you have a capacitor in that driver circuit?

Time CPU Used by Process

I've managed to implement the code on this listing to get a list of all the processes running and their IDs. What I need now is to extract how much time each process uses the CPU.
I've tried referring to the keys in the code, but when I try to print 'Ticks of CPU Time' I get a zero value for all of the processes. Plus, even if I did get a value I'm not sure if 'Ticks of CPU Time' is exactly what I'm looking for.
struct vmspace *p_vmspace; /* Address space. */
struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */
int p_flag; /* P_* flags. */
char p_stat; /* S* process status. */
pid_t p_pid; /* Process identifier. */
pid_t p_oppid; /* Save parent pid during ptrace. XXX */
int p_dupfd; /* Sideways return value from fdopen. XXX */
/* Mach related */
caddr_t user_stack; /* where user stack was allocated */
void *exit_thread; /* XXX Which thread is exiting? */
int p_debugger; /* allow to debug */
boolean_t sigwait; /* indication to suspend */
/* scheduling */
u_int p_estcpu; /* Time averaged value of p_cpticks. */
int p_cpticks; /* Ticks of cpu time. */
fixpt_t p_pctcpu; /* %cpu for this process during p_swtime */
void *p_wchan; /* Sleep address. */
char *p_wmesg; /* Reason for sleep. */
u_int p_swtime; /* Time swapped in or out. */
u_int p_slptime; /* Time since last blocked. */
struct itimerval p_realtimer; /* Alarm timer. */
struct timeval p_rtime; /* Real time. */
u_quad_t p_uticks; /* Statclock hits in user mode. */
u_quad_t p_sticks; /* Statclock hits in system mode. */
u_quad_t p_iticks; /* Statclock hits processing intr. */
int p_traceflag; /* Kernel trace points. */
struct vnode *p_tracep; /* Trace to vnode. */
int p_siglist; /* DEPRECATED */
struct vnode *p_textvp; /* Vnode of executable. */
int p_holdcnt; /* If non-zero, don't swap. */
sigset_t p_sigmask; /* DEPRECATED. */
sigset_t p_sigignore; /* Signals being ignored. */
sigset_t p_sigcatch; /* Signals being caught by user. */
u_char p_priority; /* Process priority. */
u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */
char p_nice; /* Process "nice" value. */
char p_comm[MAXCOMLEN+1];
struct pgrp *p_pgrp; /* Pointer to process group. */
struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */
u_short p_xstat; /* Exit status for wait; also stop signal. */
u_short p_acflag; /* Accounting flags. */
struct rusage *p_ru; /* Exit information. XXX */
In fact I've also tried to print Time averaged value of p_cpticks and a few others and never got interesting values. Here is my code which is printing the information retrieved (I got it from cocoabuilder.com) :
- (NSDictionary *) getProcessList {
NSMutableDictionary *ProcList = [[NSMutableDictionary alloc] init];
kinfo_proc *mylist;
size_t mycount = 0;
mylist = (kinfo_proc *)malloc(sizeof(kinfo_proc));
GetBSDProcessList(&mylist, &mycount);
printf("There are %d processes.\n", (int)mycount);
NSLog(#" = = = = = = = = = = = = = = =");
int k;
for(k = 0; k < mycount; k++) {
kinfo_proc *proc = NULL;
proc = &mylist[k];
// NSString *processName = [NSString stringWithFormat: #"%s",proc->kp_proc.p_comm];
//[ ProcList setObject: processName forKey: processName ];
// [ ProcList setObject: proc->kp_proc.p_pid forKey: processName];
// printf("ID: %d - NAME: %s\n", proc->kp_proc.p_pid, proc->kp_proc.p_comm);
printf("ID: %d - NAME: %s CPU TIME: %d \n", proc->kp_proc.p_pid, proc->kp_proc.p_comm, proc->kp_proc.p_pid );
// Right click on p_comm and select 'jump to definition' to find other values.
}
free(mylist);
return [ProcList autorelease];
}
Thanks!
EDIT: I've just offered a bounty for this question. What I'm looking for specifically is to get the amount of time each process spends in CPU.
If, in addition to this, you can give %CPU being used by a process, that would be fantastic.
The code should be optimal in that it will be called every second and the method will be called on all running processes. Objective-C preferable.
Thanks again!
EDIT 2
Also, any comments as to why people are ignoring this question would also be helpful :)
Have a look at the Darwin source for libtop.c and particularly the libtop_pinfo_update_cpu_usage() function. Note that:
You'll need a basic understanding of Mach programming fundamentals to make sense of this code, as it uses task ports, etc.
If you want to simply use libtop, you'll have to download the source and compile it yourself.
Your process will need privileges to get at the task ports for other processes.
If all this sounds rather daunting, well… There is a way that uses less esoteric APIs: Just spawn a top process and parse its standard output. A quick glimpse over the top(1) man page turned up this little gem:
$ top -s 1 -l 3600 -stats pid,cpu,time
That is, sample once per second for 3600 seconds (one hour), and output to stdout in log form only the statistics for pid, cpu usage, and time.
Spawning and managing the child top process and then parsing its output are all straightforward Unix programming exercises.
Have you taken a look at the struct rusage? You have listed it and commented as "Exit information" but I know that it contains the resources actually used by a process. Take a look at this page. I remember I used getrusage() for calculating the exact amount of CPU time used in my scientific calculation for my current process, so you just have to know how to query that struct for each process in you list i guess