1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Pass timeout to optimistic_yield, add cont_can_yield check

This commit is contained in:
Ivan Grokhotkov 2015-07-20 15:48:25 +03:00
parent 01361fc4c8
commit e5d2ba5db8
11 changed files with 193 additions and 177 deletions

View File

@ -38,9 +38,6 @@ extern "C" {
#include "esp8266_peri.h"
#include "twi.h"
void yield(void);
void optimistic_yield(void);
#define HIGH 0x1
#define LOW 0x0
@ -140,8 +137,8 @@ void timer0_detachInterrupt(void);
void ets_intr_lock();
void ets_intr_unlock();
// level (0-15),
// level 15 will disable ALL interrupts,
// level (0-15),
// level 15 will disable ALL interrupts,
// level 0 will disable most software interrupts
//
#define xt_disable_interrupts(state, level) __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state))
@ -207,6 +204,9 @@ void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
void yield(void);
void optimistic_yield(uint32_t interval_us);
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
#define digitalPinToPort(pin) (0)

View File

@ -1,9 +1,9 @@
/*
/*
HardwareSerial.cpp - esp8266 UART support
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -559,7 +559,7 @@ int HardwareSerial::available(void) {
}
if (!result) {
optimistic_yield();
optimistic_yield(USD(_uart->uart_nr) / 128);
}
return result;

View File

@ -1,8 +1,8 @@
/*
/*
cont.S - continuations support for Xtensa call0 ABI
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -18,106 +18,109 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
.text
.align 4
.literal_position
.global cont_yield
.type cont_yield, @function
.text
.align 4
.literal_position
.global cont_yield
.type cont_yield, @function
cont_yield:
/* a1: sp */
/* a2: void* cont_ctx */
/* adjust stack and save registers */
addi a1, a1, -24
s32i a12, a1, 0
s32i a13, a1, 4
s32i a14, a1, 8
s32i a15, a1, 12
s32i a0, a1, 16
s32i a2, a1, 20
/* a1: sp */
/* a2: void* cont_ctx */
/* adjust stack and save registers */
addi a1, a1, -24
s32i a12, a1, 0
s32i a13, a1, 4
s32i a14, a1, 8
s32i a15, a1, 12
s32i a0, a1, 16
s32i a2, a1, 20
/* &cont_continue -> cont_ctx.pc_yield */
movi a3, cont_continue
s32i a3, a2, 8
/* sp -> cont_ctx.sp_yield */
s32i a1, a2, 12
/* &cont_continue -> cont_ctx.pc_yield */
movi a3, cont_continue
s32i a3, a2, 8
/* sp -> cont_ctx.sp_yield */
s32i a1, a2, 12
/* a0 <- cont_ctx.pc_ret */
l32i a0, a2, 0
/* sp <- cont_ctx.sp_ret */
l32i a1, a2, 4
jx a0
/* a0 <- cont_ctx.pc_ret */
l32i a0, a2, 0
/* sp <- cont_ctx.sp_ret */
l32i a1, a2, 4
jx a0
cont_continue:
l32i a12, a1, 0
l32i a13, a1, 4
l32i a14, a1, 8
l32i a15, a1, 12
l32i a0, a1, 16
l32i a2, a1, 20
addi a1, a1, 24
ret
.size cont_yield, . - cont_yield
l32i a12, a1, 0
l32i a13, a1, 4
l32i a14, a1, 8
l32i a15, a1, 12
l32i a0, a1, 16
l32i a2, a1, 20
addi a1, a1, 24
ret
.size cont_yield, . - cont_yield
////////////////////////////////////////////////////
.text
.align 4
.literal_position
.global cont_run
.type cont_run, @function
.text
.align 4
.literal_position
.global cont_run
.type cont_run, @function
cont_run:
/* a1: sp */
/* a2: void* cont_ctx */
/* a3: void (*pfn) */
/* a1: sp */
/* a2: void* cont_ctx */
/* a3: void (*pfn) */
/* adjust stack and save registers */
addi a1, a1, -20
s32i a12, a1, 0
s32i a13, a1, 4
s32i a14, a1, 8
s32i a15, a1, 12
s32i a0, a1, 16
/* adjust stack and save registers */
addi a1, a1, -20
s32i a12, a1, 0
s32i a13, a1, 4
s32i a14, a1, 8
s32i a15, a1, 12
s32i a0, a1, 16
/* cont_ret -> a4 -> cont_ctx.pc_ret*/
movi a4, cont_ret
s32i a4, a2, 0
/* sp -> cont_ctx.sp_ret */
s32i a1, a2, 4
/* cont_ret -> a4 -> cont_ctx.pc_ret*/
movi a4, cont_ret
s32i a4, a2, 0
/* sp -> cont_ctx.sp_ret */
s32i a1, a2, 4
/* if cont_ctx.pc_yield != 0, goto cont_resume */
l32i a4, a2, 8
bnez a4, cont_resume
/* else */
/* set new stack*/
l32i a1, a2, 16;
/* goto pfn */
movi a0, cont_norm
jx a3
/* if cont_ctx.pc_yield != 0, goto cont_resume */
l32i a4, a2, 8
bnez a4, cont_resume
/* else */
/* set new stack*/
l32i a1, a2, 16;
/* goto pfn */
movi a0, cont_norm
jx a3
cont_resume:
/* a1 <- cont_ctx.sp_yield */
l32i a1, a2, 12
/* reset yield flag, 0 -> cont_ctx.pc_yield */
movi a3, 0
s32i a3, a2, 8
/* jump to saved cont_ctx.pc_yield */
movi a0, cont_ret
jx a4
/* a1 <- cont_ctx.sp_yield */
l32i a1, a2, 12
/* reset yield flag, 0 -> cont_ctx.pc_yield */
movi a3, 0
s32i a3, a2, 8
/* jump to saved cont_ctx.pc_yield */
movi a0, cont_ret
jx a4
cont_norm:
/* calculate pointer to cont_ctx.struct_start from sp */
l32i a2, a1, 4
/* sp <- cont_ctx.sp_ret */
l32i a1, a2, 4
/* calculate pointer to cont_ctx.struct_start from sp */
l32i a2, a1, 4
/* sp <- cont_ctx.sp_ret */
l32i a1, a2, 4
/* 0 -> cont_ctx.pc_ret */
movi a4, 0
s32i a4, a2, 0
cont_ret:
/* restore registers */
l32i a12, a1, 0
l32i a13, a1, 4
l32i a14, a1, 8
l32i a15, a1, 12
l32i a0, a1, 16
/* adjust stack and return */
addi a1, a1, 20
ret
.size cont_run, . - cont_run
/* restore registers */
l32i a12, a1, 0
l32i a13, a1, 4
l32i a14, a1, 8
l32i a15, a1, 12
l32i a0, a1, 16
/* adjust stack and return */
addi a1, a1, 20
ret
.size cont_run, . - cont_run

View File

@ -1,8 +1,8 @@
/*
/*
cont.h - continuations support for Xtensa call0 ABI
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -21,6 +21,8 @@
#ifndef CONT_H_
#define CONT_H_
#include <stdbool.h>
#ifndef CONT_STACKSIZE
#define CONT_STACKSIZE 4096
#endif
@ -58,4 +60,8 @@ void cont_yield(cont_t*);
// return 1 if guard bytes were overwritten.
int cont_check(cont_t* cont);
// Check if yield() may be called. Returns true if we are running inside
// continuation stack
bool cont_can_yield(cont_t* cont);
#endif /* CONT_H_ */

View File

@ -1,8 +1,8 @@
/*
/*
cont_util.s - continuations support for Xtensa call0 ABI
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -19,6 +19,9 @@
*/
#include "cont.h"
#include <stddef.h>
#include "ets_sys.h"
#define CONT_STACKGUARD 0xfeefeffe
@ -34,3 +37,8 @@ int cont_check(cont_t* cont) {
return 0;
}
bool cont_can_yield(cont_t* cont) {
return !ETS_INTR_WITHINISR() &&
cont->pc_ret != 0 && cont->pc_yield == 0;
}

View File

@ -1,10 +1,10 @@
/*
/*
main.cpp - platform initialization and context switching
emulation
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -64,16 +64,16 @@ extern void (*__init_array_end)(void);
cont_t g_cont __attribute__ ((aligned (16)));
static os_event_t g_loop_queue[LOOP_QUEUE_SIZE];
static uint32_t g_micros_at_last_task_yield;
static uint32_t g_micros_at_task_start;
extern "C" void abort() {
while(1) {
}
do {
*((int*)0) = 0;
} while(true);
}
extern "C" void esp_yield() {
g_micros_at_last_task_yield = system_get_time();
cont_yield(&g_cont);
}
@ -82,16 +82,22 @@ extern "C" void esp_schedule() {
}
extern "C" void __yield() {
esp_schedule();
esp_yield();
if (cont_can_yield(&g_cont)) {
esp_schedule();
esp_yield();
}
else {
abort();
}
}
extern "C" void yield(void) __attribute__ ((weak, alias("__yield")));
extern "C" void optimistic_yield(void) {
if (!ETS_INTR_WITHINISR() &&
(system_get_time() - g_micros_at_last_task_yield) > OPTIMISTIC_YIELD_TIME_US)
extern "C" void optimistic_yield(uint32_t interval_us) {
if (cont_can_yield(&g_cont) &&
(system_get_time() - g_micros_at_task_start) > interval_us)
{
__yield();
yield();
}
}
@ -107,10 +113,10 @@ static void loop_wrapper() {
}
static void loop_task(os_event_t *events) {
g_micros_at_last_task_yield = system_get_time();
g_micros_at_task_start = system_get_time();
cont_run(&g_cont, &loop_wrapper);
if(cont_check(&g_cont) != 0) {
ets_printf("\r\nheap collided with sketch stack\r\n");
ets_printf("\r\nsketch stack overflow detected\r\n");
abort();
}
}
@ -127,13 +133,11 @@ void init_done() {
esp_schedule();
}
extern "C" {
void user_init(void) {
extern "C" void user_init(void) {
struct rst_info *rtc_info_ptr = system_get_rst_info();
memcpy((void *) &resetInfo, (void *) rtc_info_ptr, sizeof(resetInfo));
uart_div_modify(0, UART_CLK_FREQ / (115200));
init();
@ -143,10 +147,8 @@ void user_init(void) {
cont_init(&g_cont);
system_os_task(loop_task,
LOOP_TASK_PRIORITY, g_loop_queue,
LOOP_QUEUE_SIZE);
LOOP_TASK_PRIORITY, g_loop_queue,
LOOP_QUEUE_SIZE);
system_init_done_cb(&init_done);
}
}

View File

@ -1,9 +1,9 @@
/*
/*
ESP8266WiFi.cpp - WiFi library for esp8266
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -134,7 +134,7 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s
wifi_station_dhcpc_stop();
wifi_set_ip_info(STATION_IF, &info);
_useStaticIp = true;
}
@ -152,7 +152,7 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s
ip_addr_t d;
d.addr = static_cast<uint32_t>(dns);
dns_setserver(0,&d);
_useStaticIp = true;
}
@ -185,7 +185,7 @@ void ESP8266WiFiClass::softAP(const char* ssid)
{
softAP(ssid, 0);
}
void ESP8266WiFiClass::softAP(const char* ssid, const char* passphrase, int channel, int ssid_hidden)
{
@ -265,7 +265,7 @@ uint8_t* ESP8266WiFiClass::softAPmacAddress(uint8_t* mac)
wifi_get_macaddr(SOFTAP_IF, mac);
return mac;
}
String ESP8266WiFiClass::softAPmacAddress(void)
{
uint8_t mac[6];
@ -287,7 +287,7 @@ IPAddress ESP8266WiFiClass::softAPIP()
{
struct ip_info ip;
wifi_get_ip_info(SOFTAP_IF, &ip);
return IPAddress(ip.ip.addr);
return IPAddress(ip.ip.addr);
}
IPAddress ESP8266WiFiClass::subnetMask()
@ -351,7 +351,7 @@ void ESP8266WiFiClass::_scanDone(void* result, int status)
}
else
{
int i = 0;
bss_info_head_t* head = reinterpret_cast<bss_info_head_t*>(result);
@ -428,7 +428,7 @@ int8_t ESP8266WiFiClass::scanNetworks(bool async)
{
disconnect();
}
scanDelete();
struct scan_config config;
@ -592,7 +592,7 @@ int ESP8266WiFiClass::hostByName(const char* aHostname, IPAddress& aResult)
esp_yield();
// will return here when dns_found_callback fires
}
return (aResult != 0) ? 1 : 0;
}
@ -653,7 +653,7 @@ bool ESP8266WiFiClass::beginWPSConfig(void) {
disconnect();
DEBUGV("wps begin: %d\n", wps_type);
DEBUGV("wps begin\n");
if(!wifi_wps_disable()) {
DEBUGV("wps disable faild\n");
@ -702,7 +702,7 @@ void ESP8266WiFiClass::beginSmartConfig()
_smartConfigStarted = true;
_smartConfigDone = false;
//SC_TYPE_ESPTOUCH use ESPTOUCH for smartconfig, or use SC_TYPE_AIRKISS for AIRKISS
//SC_TYPE_ESPTOUCH use ESPTOUCH for smartconfig, or use SC_TYPE_AIRKISS for AIRKISS
smartconfig_start(reinterpret_cast<sc_callback_t>(&ESP8266WiFiClass::_smartConfigCallback), 1);
}
@ -728,7 +728,7 @@ void ESP8266WiFiClass::_smartConfigCallback(uint32_t st, void* result)
sc_status status = (sc_status) st;
if (status == SC_STATUS_LINK) {
station_config* sta_conf = reinterpret_cast<station_config*>(result);
wifi_station_set_config(sta_conf);
wifi_station_disconnect();
wifi_station_connect();
@ -777,7 +777,7 @@ void ESP8266WiFiClass::printDiag(Print& p)
static struct station_config conf;
wifi_station_get_config(&conf);
const char* ssid = reinterpret_cast<const char*>(conf.ssid);
p.print("SSID (");
p.print(strlen(ssid));

View File

@ -1,10 +1,10 @@
/*
/*
WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible
with Arduino WiFi shield library
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -22,7 +22,7 @@
#define LWIP_INTERNAL
extern "C"
extern "C"
{
#include "include/wl_definitions.h"
#include "osapi.h"
@ -48,7 +48,7 @@ template<>
WiFiClient* SList<WiFiClient>::_s_first = 0;
WiFiClient::WiFiClient()
WiFiClient::WiFiClient()
: _client(0)
{
WiFiClient::_add(this);
@ -78,7 +78,7 @@ WiFiClient::WiFiClient(const WiFiClient& other)
WiFiClient& WiFiClient::operator=(const WiFiClient& other)
{
if (_client)
_client->unref();
_client->unref();
_client = other._client;
if (_client)
_client->ref();
@ -86,7 +86,7 @@ WiFiClient& WiFiClient::operator=(const WiFiClient& other)
}
int WiFiClient::connect(const char* host, uint16_t port)
int WiFiClient::connect(const char* host, uint16_t port)
{
IPAddress remote_addr;
if (WiFi.hostByName(host, remote_addr))
@ -96,7 +96,7 @@ int WiFiClient::connect(const char* host, uint16_t port)
return 0;
}
int WiFiClient::connect(IPAddress ip, uint16_t port)
int WiFiClient::connect(IPAddress ip, uint16_t port)
{
ip_addr_t addr;
addr.addr = ip;
@ -162,12 +162,12 @@ bool WiFiClient::getNoDelay() {
return _client->getNoDelay();
}
size_t WiFiClient::write(uint8_t b)
size_t WiFiClient::write(uint8_t b)
{
return write(&b, 1);
}
size_t WiFiClient::write(const uint8_t *buf, size_t size)
size_t WiFiClient::write(const uint8_t *buf, size_t size)
{
if (!_client || !size)
{
@ -179,19 +179,18 @@ size_t WiFiClient::write(const uint8_t *buf, size_t size)
int WiFiClient::available()
{
int result = 0;
if (!_client)
return false;
if (_client) {
result = _client->getSize();
}
int result = _client->getSize();
if (!result) {
optimistic_yield();
optimistic_yield(100);
}
return result;
}
int WiFiClient::read()
int WiFiClient::read()
{
if (!available())
return -1;
@ -200,12 +199,12 @@ int WiFiClient::read()
}
int WiFiClient::read(uint8_t* buf, size_t size)
int WiFiClient::read(uint8_t* buf, size_t size)
{
return (int) _client->read(reinterpret_cast<char*>(buf), size);
}
int WiFiClient::peek()
int WiFiClient::peek()
{
if (!available())
return -1;
@ -213,13 +212,13 @@ int WiFiClient::peek()
return _client->peek();
}
void WiFiClient::flush()
void WiFiClient::flush()
{
if (_client)
_client->flush();
}
void WiFiClient::stop()
void WiFiClient::stop()
{
if (!_client)
return;
@ -228,7 +227,7 @@ void WiFiClient::stop()
_client = 0;
}
uint8_t WiFiClient::connected()
uint8_t WiFiClient::connected()
{
if (!_client)
return 0;
@ -236,14 +235,14 @@ uint8_t WiFiClient::connected()
return _client->state() == ESTABLISHED || available();
}
uint8_t WiFiClient::status()
uint8_t WiFiClient::status()
{
if (!_client)
return CLOSED;
return _client->state();
}
WiFiClient::operator bool()
WiFiClient::operator bool()
{
return _client != 0;
}

View File

@ -1,10 +1,10 @@
/*
/*
WiFiServer.cpp - TCP/IP server for esp8266, mostly compatible
with Arduino WiFi shield library
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@ -99,7 +99,7 @@ WiFiClient WiFiServer::available(byte* status)
return result;
}
optimistic_yield();
optimistic_yield(1000);
return WiFiClient();
}
@ -161,4 +161,3 @@ void WiFiServer::_s_discard(void* server, ClientContext* ctx)
{
reinterpret_cast<WiFiServer*>(server)->_discard(ctx);
}

View File

@ -22,8 +22,8 @@
#define LWIP_INTERNAL
#include <functional>
extern "C"
extern "C"
{
#include "include/wl_definitions.h"
#include "osapi.h"
@ -45,7 +45,7 @@ template<>
WiFiUDP* SList<WiFiUDP>::_s_first = 0;
/* Constructor */
WiFiUDP::WiFiUDP() : _ctx(0)
WiFiUDP::WiFiUDP() : _ctx(0)
{
WiFiUDP::_add(this);
}
@ -74,7 +74,7 @@ WiFiUDP::~WiFiUDP()
}
/* Start WiFiUDP socket, listening at local port */
uint8_t WiFiUDP::begin(uint16_t port)
uint8_t WiFiUDP::begin(uint16_t port)
{
if (_ctx) {
_ctx->unref();
@ -94,7 +94,7 @@ uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, ui
_ctx->unref();
_ctx = 0;
}
ip_addr_t ifaddr;
ifaddr.addr = (uint32_t) interfaceAddr;
ip_addr_t multicast_addr;
@ -122,10 +122,6 @@ int WiFiUDP::available() {
result = static_cast<int>(_ctx->getSize());
}
if (!result) {
optimistic_yield();
}
return result;
}
@ -161,7 +157,7 @@ int WiFiUDP::beginPacket(IPAddress ip, uint16_t port)
return (_ctx->connect(addr, port)) ? 1 : 0;
}
int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port,
int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port,
IPAddress interfaceAddress, int ttl)
{
ip_addr_t mcastAddr;
@ -207,8 +203,12 @@ int WiFiUDP::parsePacket()
{
if (!_ctx)
return 0;
if (!_ctx->next())
if (!_ctx->next()) {
optimistic_yield(100);
return 0;
}
return _ctx->getSize();
}
@ -216,8 +216,8 @@ int WiFiUDP::read()
{
if (!_ctx)
return -1;
return _ctx->read();
return _ctx->read();
}
int WiFiUDP::read(unsigned char* buffer, size_t len)
@ -284,4 +284,3 @@ void WiFiUDP::stopAll()
it->stop();
}
}

View File

@ -65,8 +65,8 @@ inline bool ETS_INTR_WITHINISR()
{
uint32_t ps;
__asm__ __volatile__("rsr %0,ps":"=a" (ps));
// PS.EXCM and PS.UM bit checks
return ((ps & ((1 << 4) | (1 << 5))) > 0);
// PS.EXCM bit check
return ((ps & (1 << 4)) != 0);
}
inline uint32_t ETS_INTR_ENABLED(void)