🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.c
Article #310065

Coroutines w (GNU) C

#310065
From: Maciek Godek
Date: Fri, 24 Jan 2020 11:44
65 lines
3426 bytes
Jeśli by to kogoś interesowało, to dziś "wymyśliłem" prosty sposób na implementację "coroutines" w C.

Pomysł opiera się na rozszerzeniu kompilatora GCC pozwalającym na przechowywanie etykiet dla goto w zmiennych, i możliwości skakania do tych zmiennych:

https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html

Interfejs jest taki, że na początku funkcji musimy wywołać makro

COROUTINE_START()

i dalej możemy użyć

COROUTINE_RETURN(wartość)

co zadziała jak normalne wyjście z funkcji, albo

COROUTINE_YIELD(wartość)

co spowoduje przerwanie egzekucji funkcji, przy czym kolejne wywołanie
funkcji spowoduje jej kontynuowanie za ostatnio wykonanym wyrażeniem COROUTINE_YIELD.

Na przykład kod może wyglądać tak:

int coroutine() {
  COROUTINE_START();

  printf("started\n");
  COROUTINE_YIELD(1);

  printf("stage 1\n");
  COROUTINE_YIELD(2);

  printf("stage 2"\n");
  COROUTINE_YIELD(3);

  printf("finishing\n");
  COROUTINE_RETURN(4);
}

Drobny problem jest z przekazywaniem parametrów: jeżeli chcemy, żeby wartości argumentów były przechowywane między wywołaniami, to musimy je zapisywać w zmiennych statycznych.

Implementacja składa się z nieco ponad 20 linii kodu:

#define COROUTINE_START()                               \
    static void *coroutine_continuation =               \
        &&coroutine_start;                              \
    goto *coroutine_continuation;                       \
coroutine_start:                                        \
 do {} while(0)
    
#define COROUTINE_RESTART                       \
    coroutine_continuation = &&coroutine_start

#define COROUTINE_RETURN(...)                   \
    COROUTINE_RESTART; return __VA_ARGS__

#define _COROUTINE_LABEL(line) coroutine_##line
#define COROUTINE_LABEL(line) _COROUTINE_LABEL(line)

#define COROUTINE_YIELD(...)                            \
    coroutine_continuation =                            \
        &&COROUTINE_LABEL(__LINE__);                    \
    return __VA_ARGS__;                                 \
COROUTINE_LABEL(__LINE__):                              \
 do {} while(0)
Technical Details
Message-ID: <4375b52d-ba21-462a-8844-9bd1a02e9ece@googlegroups.com>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!news-2.dfn.de!news.dfn.de!2.eu.feeder.erje.net!3.eu.feeder.erje.net!feeder.erje.net!weretis.net!feeder7.news.weretis.net!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!g89no5870741qtd.0!news-out.google.com!w29ni238qtc.0!nntp.google.com!g89no5870736qtd.0!postnews.google.com!google-groups.googlegroups.com!not-for-mail

Show Full Headers
Complete Article Headers
X-Received: by 2002:a05:6214:1634:: with SMTP id e20mr2266451qvw.205.1579866254837;        Fri, 24 Jan 2020 03:44:14 -0800 (PST)
X-Received: by 2002:a25:afd1:: with SMTP id d17mr1953953ybj.92.1579866254621; Fri, 24 Jan 2020 03:44:14 -0800 (PST)
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!news-2.dfn.de!news.dfn.de!2.eu.feeder.erje.net!3.eu.feeder.erje.net!feeder.erje.net!weretis.net!feeder7.news.weretis.net!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!g89no5870741qtd.0!news-out.google.com!w29ni238qtc.0!nntp.google.com!g89no5870736qtd.0!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: pl.comp.lang.c
Date: Fri, 24 Jan 2020 03:44:14 -0800 (PST)
Complaints-To: groups-abuse@google.com
Injection-Info: google-groups.googlegroups.com; posting-host=213.192.68.153; posting-account=f7iIKQoAAAAkDKpUafc-4IXhmRAzdB5r
NNTP-Posting-Host: 213.192.68.153
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <4375b52d-ba21-462a-8844-9bd1a02e9ece@googlegroups.com>
Subject: Coroutines w (GNU) C
From: Maciek Godek <godek.maciek@gmail.com>
Injection-Date: Fri, 24 Jan 2020 11:44:14 +0000
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit