- 新增图像生成接口,支持试用、积分和自定义API Key模式 - 实现生成图片结果异步上传至MinIO存储,带重试机制 - 优化积分预扣除和异常退还逻辑,保障用户积分准确 - 添加获取生成历史记录接口,支持时间范围和分页 - 提供本地字典配置接口,支持模型、比例、提示模板和尺寸 - 实现图片批量上传接口,支持S3兼容对象存储 feat(admin): 增加管理员角色管理与权限分配接口 - 实现角色列表查询、角色创建、更新及删除功能 - 增加权限列表查询接口 - 实现用户角色分配接口,便于统一管理用户权限 - 增加系统字典增删查改接口,支持分类过滤和排序 - 权限控制全面覆盖管理接口,保证安全访问 feat(auth): 完善用户登录注册及权限相关接口与页面 - 实现手机号验证码发送及校验功能,保障注册安全 - 支持手机号注册、登录及退出接口,集成日志记录 - 增加修改密码功能,验证原密码后更新 - 提供动态导航菜单接口,基于权限展示不同菜单 - 实现管理界面路由及日志、角色、字典管理页面访问权限控制 - 添加系统日志查询接口,支持关键词和等级筛选 feat(app): 初始化Flask应用并配置蓝图与数据库 - 创建应用程序工厂,加载配置,初始化数据库和Redis客户端 - 注册认证、API及管理员蓝图,整合路由 - 根路由渲染主页模板 - 应用上下文中自动创建数据库表,保证运行环境准备完毕 feat(database): 提供数据库创建与迁移支持脚本 - 新增数据库创建脚本,支持自动检测是否已存在 - 添加数据库表初始化脚本,支持创建和删除所有表 - 实现RBAC权限初始化,包含基础权限和角色创建 - 新增字段手动修复脚本,添加用户API Key和积分字段 - 强制迁移脚本支持清理连接和修复表结构,初始化默认数据及角色分配 feat(config): 新增系统配置参数 - 配置数据库、Redis、Session和MinIO相关参数 - 添加AI接口地址及试用Key配置 - 集成阿里云短信服务配置及开发模式相关参数 feat(extensions): 初始化数据库、Redis和MinIO客户端 - 创建全局SQLAlchemy数据库实例和Redis客户端 - 配置基于boto3的MinIO兼容S3客户端 chore(logs): 添加示例系统日志文件 - 记录用户请求、验证码发送成功与失败的日志信息
266 lines
7.2 KiB
C++
266 lines
7.2 KiB
C++
#ifndef GREENLET_STACK_STATE_CPP
|
|
#define GREENLET_STACK_STATE_CPP
|
|
|
|
#include "TGreenlet.hpp"
|
|
|
|
namespace greenlet {
|
|
|
|
#ifdef GREENLET_USE_STDIO
|
|
#include <iostream>
|
|
using std::cerr;
|
|
using std::endl;
|
|
|
|
std::ostream& operator<<(std::ostream& os, const StackState& s)
|
|
{
|
|
os << "StackState(stack_start=" << (void*)s._stack_start
|
|
<< ", stack_stop=" << (void*)s.stack_stop
|
|
<< ", stack_copy=" << (void*)s.stack_copy
|
|
<< ", stack_saved=" << s._stack_saved
|
|
<< ", stack_prev=" << s.stack_prev
|
|
<< ", addr=" << &s
|
|
<< ")";
|
|
return os;
|
|
}
|
|
#endif
|
|
|
|
StackState::StackState(void* mark, StackState& current)
|
|
: _stack_start(nullptr),
|
|
stack_stop((char*)mark),
|
|
stack_copy(nullptr),
|
|
_stack_saved(0),
|
|
/* Skip a dying greenlet */
|
|
stack_prev(current._stack_start
|
|
? ¤t
|
|
: current.stack_prev)
|
|
{
|
|
}
|
|
|
|
StackState::StackState()
|
|
: _stack_start(nullptr),
|
|
stack_stop(nullptr),
|
|
stack_copy(nullptr),
|
|
_stack_saved(0),
|
|
stack_prev(nullptr)
|
|
{
|
|
}
|
|
|
|
StackState::StackState(const StackState& other)
|
|
// can't use a delegating constructor because of
|
|
// MSVC for Python 2.7
|
|
: _stack_start(nullptr),
|
|
stack_stop(nullptr),
|
|
stack_copy(nullptr),
|
|
_stack_saved(0),
|
|
stack_prev(nullptr)
|
|
{
|
|
this->operator=(other);
|
|
}
|
|
|
|
StackState& StackState::operator=(const StackState& other)
|
|
{
|
|
if (&other == this) {
|
|
return *this;
|
|
}
|
|
if (other._stack_saved) {
|
|
throw std::runtime_error("Refusing to steal memory.");
|
|
}
|
|
|
|
//If we have memory allocated, dispose of it
|
|
this->free_stack_copy();
|
|
|
|
this->_stack_start = other._stack_start;
|
|
this->stack_stop = other.stack_stop;
|
|
this->stack_copy = other.stack_copy;
|
|
this->_stack_saved = other._stack_saved;
|
|
this->stack_prev = other.stack_prev;
|
|
return *this;
|
|
}
|
|
|
|
inline void StackState::free_stack_copy() noexcept
|
|
{
|
|
PyMem_Free(this->stack_copy);
|
|
this->stack_copy = nullptr;
|
|
this->_stack_saved = 0;
|
|
}
|
|
|
|
inline void StackState::copy_heap_to_stack(const StackState& current) noexcept
|
|
{
|
|
|
|
/* Restore the heap copy back into the C stack */
|
|
if (this->_stack_saved != 0) {
|
|
memcpy(this->_stack_start, this->stack_copy, this->_stack_saved);
|
|
this->free_stack_copy();
|
|
}
|
|
StackState* owner = const_cast<StackState*>(¤t);
|
|
if (!owner->_stack_start) {
|
|
owner = owner->stack_prev; /* greenlet is dying, skip it */
|
|
}
|
|
while (owner && owner->stack_stop <= this->stack_stop) {
|
|
// cerr << "\tOwner: " << owner << endl;
|
|
owner = owner->stack_prev; /* find greenlet with more stack */
|
|
}
|
|
this->stack_prev = owner;
|
|
// cerr << "\tFinished with: " << *this << endl;
|
|
}
|
|
|
|
inline int StackState::copy_stack_to_heap_up_to(const char* const stop) noexcept
|
|
{
|
|
/* Save more of g's stack into the heap -- at least up to 'stop'
|
|
g->stack_stop |________|
|
|
| |
|
|
| __ stop . . . . .
|
|
| | ==> . .
|
|
|________| _______
|
|
| | | |
|
|
| | | |
|
|
g->stack_start | | |_______| g->stack_copy
|
|
*/
|
|
intptr_t sz1 = this->_stack_saved;
|
|
intptr_t sz2 = stop - this->_stack_start;
|
|
assert(this->_stack_start);
|
|
if (sz2 > sz1) {
|
|
char* c = (char*)PyMem_Realloc(this->stack_copy, sz2);
|
|
if (!c) {
|
|
PyErr_NoMemory();
|
|
return -1;
|
|
}
|
|
memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1);
|
|
this->stack_copy = c;
|
|
this->_stack_saved = sz2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
inline int StackState::copy_stack_to_heap(char* const stackref,
|
|
const StackState& current) noexcept
|
|
{
|
|
/* must free all the C stack up to target_stop */
|
|
const char* const target_stop = this->stack_stop;
|
|
|
|
StackState* owner = const_cast<StackState*>(¤t);
|
|
assert(owner->_stack_saved == 0); // everything is present on the stack
|
|
if (!owner->_stack_start) {
|
|
owner = owner->stack_prev; /* not saved if dying */
|
|
}
|
|
else {
|
|
owner->_stack_start = stackref;
|
|
}
|
|
|
|
while (owner->stack_stop < target_stop) {
|
|
/* ts_current is entierely within the area to free */
|
|
if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) {
|
|
return -1; /* XXX */
|
|
}
|
|
owner = owner->stack_prev;
|
|
}
|
|
if (owner != this) {
|
|
if (owner->copy_stack_to_heap_up_to(target_stop)) {
|
|
return -1; /* XXX */
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
inline bool StackState::started() const noexcept
|
|
{
|
|
return this->stack_stop != nullptr;
|
|
}
|
|
|
|
inline bool StackState::main() const noexcept
|
|
{
|
|
return this->stack_stop == (char*)-1;
|
|
}
|
|
|
|
inline bool StackState::active() const noexcept
|
|
{
|
|
return this->_stack_start != nullptr;
|
|
}
|
|
|
|
inline void StackState::set_active() noexcept
|
|
{
|
|
assert(this->_stack_start == nullptr);
|
|
this->_stack_start = (char*)1;
|
|
}
|
|
|
|
inline void StackState::set_inactive() noexcept
|
|
{
|
|
this->_stack_start = nullptr;
|
|
// XXX: What if we still have memory out there?
|
|
// That case is actually triggered by
|
|
// test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks)
|
|
// and
|
|
// test_issue251_issue252_need_to_collect_in_background
|
|
// (greenlet.tests.test_leaks.TestLeaks)
|
|
//
|
|
// Those objects never get deallocated, so the destructor never
|
|
// runs.
|
|
// It *seems* safe to clean up the memory here?
|
|
if (this->_stack_saved) {
|
|
this->free_stack_copy();
|
|
}
|
|
}
|
|
|
|
inline intptr_t StackState::stack_saved() const noexcept
|
|
{
|
|
return this->_stack_saved;
|
|
}
|
|
|
|
inline char* StackState::stack_start() const noexcept
|
|
{
|
|
return this->_stack_start;
|
|
}
|
|
|
|
|
|
inline StackState StackState::make_main() noexcept
|
|
{
|
|
StackState s;
|
|
s._stack_start = (char*)1;
|
|
s.stack_stop = (char*)-1;
|
|
return s;
|
|
}
|
|
|
|
StackState::~StackState()
|
|
{
|
|
if (this->_stack_saved != 0) {
|
|
this->free_stack_copy();
|
|
}
|
|
}
|
|
|
|
void StackState::copy_from_stack(void* vdest, const void* vsrc, size_t n) const
|
|
{
|
|
char* dest = static_cast<char*>(vdest);
|
|
const char* src = static_cast<const char*>(vsrc);
|
|
if (src + n <= this->_stack_start
|
|
|| src >= this->_stack_start + this->_stack_saved
|
|
|| this->_stack_saved == 0) {
|
|
// Nothing we're copying was spilled from the stack
|
|
memcpy(dest, src, n);
|
|
return;
|
|
}
|
|
|
|
if (src < this->_stack_start) {
|
|
// Copy the part before the saved stack.
|
|
// We know src + n > _stack_start due to the test above.
|
|
const size_t nbefore = this->_stack_start - src;
|
|
memcpy(dest, src, nbefore);
|
|
dest += nbefore;
|
|
src += nbefore;
|
|
n -= nbefore;
|
|
}
|
|
// We know src >= _stack_start after the before-copy, and
|
|
// src < _stack_start + _stack_saved due to the first if condition
|
|
size_t nspilled = std::min<size_t>(n, this->_stack_start + this->_stack_saved - src);
|
|
memcpy(dest, this->stack_copy + (src - this->_stack_start), nspilled);
|
|
dest += nspilled;
|
|
src += nspilled;
|
|
n -= nspilled;
|
|
if (n > 0) {
|
|
// Copy the part after the saved stack
|
|
memcpy(dest, src, n);
|
|
}
|
|
}
|
|
|
|
}; // namespace greenlet
|
|
|
|
#endif // GREENLET_STACK_STATE_CPP
|