LINUX.ORG.RU

Может быть, Вам нужно глянуть в info gcc на предмет функций __builtin_return_addr(), __builtin_frame_address()?

ДВ

DmVo
()

Может всё-таки stack unwind? А если нет, то поясните, что Вы имеете в виду.

anonymous
()

Спасибо за ответы.
Но этот метод применяется при переключении контекста (между потоками или задачами).
"context switching is done by stack rewinding"
Если кто-то работал с такими вещами буду рад любой наводящей информации.


anonymous
()

Спасибо за ответы.
Но этот метод применяется при переключении контекста (между потоками или задачами).
"context switching is done by stack rewinding"
Если кто-то работал с такими вещами буду рад любой наводящей информации.


anonymous
()
Ответ на: комментарий от anonymous

я когда-то для баловства делал контекст-свитчинг с помощью setjmp/longjmp. Правда теперь не могу понять как оно работало, потому что не должно..

dilmah ★★★★★
()
Ответ на: комментарий от anonymous

ну в общем я разрыл архивы.. Как я и ожидал, это не совсем то что может хотеться. longjmp может передавать только вверх по дереву вызовов. Поэтому для контекст-свитчинга нужно делать дополнительную инструментировку кода. Во первых функциям передается дополнительный аргумент HpThread *. Во вторых, сам вызов и возврат обрамляются в макросы. Вызывать просто функции без обрамления макросами тоже можно но внутри них тогда нельзя переключать контексты..

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

вот hpscheduler.h:

ifndef _HPSCHEDULE_H_
#define _HPSCHEDULE_H_

#include <setjmp.h>
#include <stddef.h>
#include <stdlib.h>

#include <iostream.h>

#include "hpassert.h"

#define HP_BALZ_PER_QUANT 100

typedef struct HpScheduler
{
    struct HpThread *free;
    struct HpThread **memref;
    int memref_size;
    int memref_alloc_size;
} HpScheduler;

typedef struct HpThread
{
    jmp_buf env;
    HpScheduler *scheduler;
    struct HpThread *next[2];
    struct HpThread *master;
    void *locals;
    int quant;
    int coun;
} HpThread;

#define HP_SCHEDULE( THREAD, BALZ )                                \
{                                                                  \
    while ( (THREAD)->coun < (BALZ) )                              \
    {                                                              \
        _HP_SWITCH_STUFF( THREAD );                                \
    }                                                              \
    (THREAD)->coun -= (BALZ);                                      \
}

#define HP_SELF( THREAD, T ) ((T *)(THREAD)->locals)

#define HP_SWITCH( THREAD )                                         \
{                                                                   \
    _HP_SWITCH_STUFF( THREAD );                                     \
    (THREAD)->coun = (THREAD)->quant;                               \
}

#define HP_FORK( THREAD, FUNC )                               \
{                                                             \
    HpThread *aux;                                            \
    aux = (HpThread *)setjmp( (THREAD)->env );                \
    if ( aux == 0 )                                           \
    {                                                         \
	FUNC( _hpCreateThread( THREAD ) );                    \
    }                                                         \
    (THREAD) = aux;                                           \
}

#define HP_FORK_PLUS_PLUS( THREAD, OBJ, FUNC )                \
{                                                             \
    HpThread *aux;                                            \
    aux = (HpThread *)setjmp( (THREAD)->env );                \
    if ( aux == 0 )                                           \
    {                                                         \
        aux = _hpCreateThread( THREAD );                      \
        aux->locals = (OBJ);                                  \
	(OBJ)->FUNC( aux );                                   \
    }                                                         \
    (THREAD) = aux;                                           \
}

#define HP_RENICE( THREAD, QUANT ) \
{                                  \
    (THREAD)->quant = (QUANT);     \
}

#define HP_CALL( THREAD, FUNC )                               \
{                                                             \
    _HP_CALL_START( THREAD );                                 \
	FUNC( aux );                                          \
    _HP_CALL_END( THREAD );                                   \
}

#define HP_CALL1( THREAD, FUNC, ARG )                         \
{                                                             \
    _HP_CALL_START( THREAD );                                 \
	FUNC( aux, ARG );                                     \
    _HP_CALL_END( THREAD );                                   \
}

#define HP_CALL2( THREAD, FUNC, A1, A2 )                      \
{                                                             \
    _HP_CALL_START( THREAD );                                 \
	FUNC( aux, A1, A2 );                                  \
    _HP_CALL_END( THREAD );                                   \
}

#define HP_CALL_PLUS_PLUS( THREAD, OBJ, FUNC )                \
{                                                             \
    _HP_CALL_START( THREAD );                                 \
        aux->locals = (OBJ);                                  \
        (OBJ)->FUNC( aux );                                   \
    _HP_CALL_END( THREAD );                                   \
}

#define HP_CALL1_PLUS_PLUS( THREAD, OBJ, FUNC, ARG )          \
{                                                             \
    _HP_CALL_START( THREAD );                                 \
        aux->locals = (OBJ);                                  \
        (OBJ)->FUNC( aux, ARG );                              \
    _HP_CALL_END( THREAD );                                   \
}

#define HP_CALL2_PLUS_PLUS( THREAD, OBJ, FUNC, A1, A2 )       \
{                                                             \
    _HP_CALL_START( THREAD );                                 \
        aux->locals = (OBJ);                                  \
        (OBJ)->FUNC( aux, A1, A2 );                           \
    _HP_CALL_END( THREAD );                                   \
}

#define HP_RET( THREAD )                           \
{                                                  \
    _HP_FREE_THREAD( (THREAD)->master );           \
    (THREAD)->env = (THREAD)->master->env;                                      \
    (THREAD)->locals = (THREAD)->master->locals;                                \
    (THREAD)->master = (THREAD)->master->master;                                \
    _HP_SWITCH( THREAD );                                                       \
}

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

typedef int HpLock;

#define HP_INIT_LOCK( LOCK ) (LOCK) = 0

#define HP_SET_LOCK( THREAD, LOCK )\
{                                  \
    _HP_CHECK_LOCK( THREAD, LOCK );\
    (LOCK) = 1;                    \
}

#define HP_DROP_LOCK( THREAD, LOCK )  \
{                                     \
    (LOCK) = 0;                       \
    HP_SCHEDULE( THREAD, 1 );         \
}

#define HP_SAVE( buf, local ) (buf) = (local)

HpThread *hpStartScheduler();
void hpRenice( HpThread *, int quant );
void hpKill( HpThread *, HpThread *victim );
void hpZapScheduler( HpThread * );

/*******************************************************************************
*********\
*                                    Private parts                                       *
\*******************************************************************************
*********/

void _hpHogFreeThreads( HpScheduler *scheduler );
HpThread *_hpCreateThread( HpThread * );

#define _HP_SWITCH( THREAD )                                      \
{                                                                 \
 /* cout << "SWITCHING TO THREAD " << (void *)(THREAD) << endl;*/ \
    longjmp( (THREAD)->env, (int)(THREAD) );                      \
}

#define _HP_SWITCH_STUFF( THREAD )                                  \
{                                                                   \
    HpThread *aux;                                                  \
    aux = (HpThread *)setjmp( (THREAD)->env );                      \
    if ( aux == 0 )                                                 \
    {                                                               \
        (THREAD)->coun += (THREAD)->quant;                          \
        aux = (THREAD)->next[0];                                    \
        while ( rand() % 256 != 33 )                                \
        {                                                           \
            aux = aux->next[0];                                     \
        }                                                           \
        _HP_SWITCH( aux );                                          \
    }                                                               \
    (THREAD) = aux;                                                 \
}                                                                   \

#define _HP_CALL_START( THREAD )                              \
    HpThread *aux;                                            \
    aux = (HpThread *)setjmp( (THREAD)->env );                \
    if ( aux == 0 )                                           \
    {                                                         \
	HpScheduler *scheduler = (THREAD)->scheduler;         \
        aux = (THREAD);                                       \
	_HP_GET_THREAD( scheduler, THREAD );                  \
        _HP_CP_CHILD( THREAD, aux );                          \
	aux->master = (THREAD);

#define _HP_CALL_END( THREAD )                                \
    }                                                         \
    (THREAD) = aux;

#define _HP_CHECK_SCHEDULER( SCHED )\
{                                   \
    if ( (SCHED)->free == 0 )       \
    {                               \
	_hpHogFreeThreads( SCHED ); \
    }                               \
}

#define _HP_GET_THREAD( SCHED, aux ) \
{                                    \
    _HP_CHECK_SCHEDULER( SCHED );    \
    (aux) = (SCHED)->free;           \
    (SCHED)->free = (aux)->next[0];  \
    (aux)->scheduler = (SCHED);      \
}

#define _HP_FREE_THREAD( THREAD )                     \
{                                                     \
    (THREAD)->next[0] = (THREAD)->scheduler->free;    \
    (THREAD)->scheduler->free = (THREAD);             \
}

#define _HP_CP_CHILD( DST, SRC )                                  \
{                                                                 \
    (DST)->env = (SRC)->env;                                      \
    (DST)->coun = (SRC)->coun;                                    \
    (DST)->quant = (SRC)->quant;                                  \
    (DST)->locals = (SRC)->locals;                                \
    (DST)->master = (SRC)->master; /* should be the last line! */ \
}

#define _HP_CHECK_LOCK( THREAD, LOCK )\
{                                     \
    while ( LOCK )                    \
    {                                 \
	HP_SCHEDULE( THREAD, 10 );    \
    }                                 \
}

#endif

/* end of file */

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

вот hpscheduler.cpp:

#include <stdlib.h>

#include "hpscheduler.h"

#define HP_SCHEDULER_MEMREF_HOG 10
#define HP_SCHEDULER_THREADS_HOG 1000

#define HP_MAKE_LOCAL( T, PTR, VAR ) T VAR = PTR->VAR
#define HP_FLUSH_LOCAL( PTR, VAR ) PTR->VAR = VAR

void _hpHogFreeThreads( HpScheduler *scheduler )
{
    int i;
    HpThread *free;
    HpThread *ptr[2];

    HP_MAKE_LOCAL( HpThread **, scheduler, memref );
    HP_MAKE_LOCAL( int, scheduler, memref_size );
    HP_MAKE_LOCAL( int, scheduler, memref_alloc_size );

    if ( memref_size >= memref_alloc_size )
    {
	memref_alloc_size += HP_SCHEDULER_MEMREF_HOG;
	memref = (HpThread **)realloc( memref, memref_alloc_size * sizeof( HpThread * ) );
	HP_FLUSH_LOCAL( scheduler, memref );
	HP_FLUSH_LOCAL( scheduler, memref_alloc_size );
    }
    free = (HpThread *)malloc( HP_SCHEDULER_THREADS_HOG * sizeof( HpThread ) );
    ptr[0] = memref[memref_size++] = free;
    ptr[1] = ptr[0] + 1;
    for ( i = HP_SCHEDULER_THREADS_HOG - 1; i--; ptr[0] = ptr[1]++ )
    {
	ptr[0]->next[0] = ptr[1];
    }
    ptr[1]->next[0] = 0;
    HP_FLUSH_LOCAL( scheduler, memref_size );
    HP_FLUSH_LOCAL( scheduler, free );
}

HpThread *hpStartScheduler()
{
    HpScheduler *scheduler;
    HpThread *thread;

    scheduler = (HpScheduler *)malloc( sizeof( HpScheduler ) );
    scheduler->free = 0;
    scheduler->memref = 0;
    scheduler->memref_size = scheduler->memref_alloc_size = 0;
    scheduler->free = 0;
    _HP_GET_THREAD( scheduler, thread );
    thread->next[0] = thread->next[1] = thread;
    thread->master = 0;
    thread->quant = HP_BALZ_PER_QUANT;
    thread->coun = 0;
    return thread;
}

HpThread *_hpCreateThread( HpThread *thread )
{
    HpThread *child;

    _HP_GET_THREAD( thread->scheduler, child );
    child->next[0] = thread->next[0];
    child->next[1] = thread;
    child->master = 0;
    thread->next[0] = child;
    child->next[0]->next[1] = child;
    child->quant = HP_BALZ_PER_QUANT;
    child->coun = 0;
    return child;
}

void hpKill( HpThread *thread, HpThread *victim )
{
    HpThread *aux;

    victim->next[0]->next[1] = victim->next[1];
    victim->next[1]->next[0] = victim->next[0];
    aux = victim;
    while ( aux )
    {
	_HP_FREE_THREAD( aux );
	aux = aux->master;
    }
    if ( victim != thread )
    {
	return;
    }
    if ( victim->next[0] != thread )
    {
	_HP_SWITCH( victim->next[0] );
    }
    hpZapScheduler( thread );
}

void hpRenice( HpThread *thread, int quant )
{
    HP_RENICE( thread, quant );
}

void hpZapScheduler( HpThread *thread )
{
    int i;
    
    HP_MAKE_LOCAL( HpScheduler *, thread, scheduler );

    i = scheduler->memref_size;
    while ( i-- )
    {
	free( scheduler->memref[i] );
    }
    free( scheduler );
}

/* end of file */

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

вот пример использования:

void HpBoard::msg_handler_fight( HpThread *thread )
{
    HP_SCHEDULE( thread, 50 );
    HP_CALL1( thread, HP_BOARD->peek_cell, HP_BOARD->msg.arg[0].gps );
    cout << "ff " << HP_BOARD->msg.arg[0].gps.x << " " << HP_BOARD->msg.arg[0].gps.y << endl;
//  cout << "TERMINATION ATTEMPT " << (void *)HP_BOARD->msg.poster << " " << HP_BOARD->peeked_cell->mob << endl;
    if ( HP_BOARD->peeked_cell->mob
	 && HP_BOARD->msg.arg[0].gps.is_adjacent( ((HpMob *)(HP_BOARD->msg).poster)->gps ) )
    {
	HP_BOARD->tmp_msg.id = HP_MSG_VICTORY_REPO;
	if ( HP_IS_PREY( HP_BOARD->peeked_cell->mob )
	     && HP_IS_HUNTER( (HpMob *)(HP_BOARD->msg).poster ) )
	{
//	    cout << "DIRECT TERMINATION " << (void *)HP_BOARD->msg.poster << " " << HP_BOARD->peeked_cell->mob << endl;
	    HP_CALL1( thread, HP_BOARD->terminate, HP_BOARD->peeked_cell );
	    HP_CALL2( thread, HP_BOARD->send_message,
		      HP_BOARD->msg.poster, HP_BOARD->tmp_msg );
	}
	else if ( HP_IS_HUNTER( HP_BOARD->peeked_cell->mob )
		  && HP_IS_PREY( (HpMob *)(HP_BOARD->msg).poster ) )
	{
//	    cout << "BACK TERMINATION " << (void *)HP_BOARD->msg.poster << " " << HP_BOARD->peeked_cell->mob << endl;
	    HP_CALL1( thread, HP_BOARD->terminate, ((HpMob *)(HP_BOARD->msg).poster)->cell );
	    HP_CALL2( thread, HP_BOARD->send_message,
		      HP_BOARD->peeked_cell->mob, HP_BOARD->tmp_msg );
	}
    }
    HP_RET( thread );
}

dilmah ★★★★★
()
Ответ на: комментарий от anonymous

единственное достоинство этого кода -- что он в самом деле работает. На доске толпа жуков бегает и ест друг друга:)

Но стек rewind там полноценного нет, фактически он просто портабельно эмулируется.

dilmah ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.