add file_map

This commit is contained in:
gb 2023-12-09 18:21:05 +08:00
parent 4dc3d7ccc1
commit 1ca053bea6
12 changed files with 625 additions and 103 deletions

View File

@ -71,6 +71,10 @@ async_scanner::~async_scanner()
cfg_mgr_->clear();
delete cfg_mgr_;
}
for(auto& v: send_files_)
v->release();
send_files_.clear();
utils::uninit();
}
@ -114,6 +118,9 @@ dyn_mem_ptr async_scanner::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, pac
case PACK_CMD_FILE_READ_REQ:
reply = handle_file_send(pack, used, required);
break;
case PACK_CMD_FILE_READ_REQ_ROGER:
reply = handle_file_send_roger(pack, used, required);
break;
case PACK_CMD_SCAN_START:
reply = handle_scan_start(pack, used, required);
break;
@ -256,7 +263,7 @@ dyn_mem_ptr async_scanner::handle_file_receive(LPPACK_BASE pack, uint32_t* used,
int err = 0;
file_saver *saver = new file_saver();
err = saver->open(path.c_str(), pfi->size);
err = saver->open(path.c_str(), pfi->size, true, pfi->offset);
reply = dyn_mem::memory(base_head_size);
reply->set_len(base_head_size);
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
@ -293,7 +300,7 @@ dyn_mem_ptr async_scanner::handle_file_send(LPPACK_BASE pack, uint32_t* used, pa
int err = 0;
file_reader *reader = new file_reader();
err = reader->open(path.c_str());
err = reader->open(path.c_str(), true, pfi->offset);
reply = dyn_mem::memory(base_head_size + sizeof(TXFILE));
reply->set_len(base_head_size + sizeof(TXFILE));
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
@ -309,12 +316,52 @@ dyn_mem_ptr async_scanner::handle_file_send(LPPACK_BASE pack, uint32_t* used, pa
((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE);
((LPTXFILE)((LPPACK_BASE)reply->ptr())->payload)->size = reader->get_rest();
reader->set_packet_param(pack->cmd, pack->pack_id);
{
// move to PACK_CMD_FILE_READ_REQ_ROGER
SIMPLE_LOCK(fsender_);
send_files_.push_back(reader);
reader = nullptr;
}
}
*required = dynamic_cast<packet_data_base_ptr>(reader);
}
return reply;
}
dyn_mem_ptr async_scanner::handle_file_send_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
{
uint32_t base_head_size = sizeof(PACK_BASE);
dyn_mem_ptr reply = nullptr;
if(*used < base_head_size)
{
*used = 0;
}
else
{
file_reader* reader = nullptr;
{
SIMPLE_LOCK(fsender_);
for(size_t i = 0; i < send_files_.size(); ++i)
{
if(send_files_[i]->get_packet_id() == pack->pack_id)
{
reader = send_files_[i];
send_files_.erase(send_files_.begin() + i);
break;
}
}
}
*used = base_head_size;
*required = dynamic_cast<packet_data_base_ptr>(reader);
// if reader was nullptr, notify failed by INT or control ?
utils::to_log(LOG_LEVEL_DEBUG, "File Send beginning (%p) ...\n", reader);
}
return reply;
}
dyn_mem_ptr async_scanner::handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
{
if(!used)

View File

@ -28,6 +28,9 @@ class async_scanner : public refer
volatile bool reply_start_;
int last_err_ = 0;
MUTEX fsender_;
std::vector<file_reader*> send_files_;
dyn_mem_ptr handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
void init(void);
@ -37,6 +40,7 @@ class async_scanner : public refer
dyn_mem_ptr handle_set_opt(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
dyn_mem_ptr handle_file_receive(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
dyn_mem_ptr handle_file_send(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
dyn_mem_ptr handle_file_send_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
dyn_mem_ptr handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
dyn_mem_ptr handle_scan_stop(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
dyn_mem_ptr handle_process_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);

View File

@ -3,10 +3,11 @@
#include <string.h>
#if defined(WIN32) || defined(_WIN64)
#if OS_WIN
#else
#include <sys/fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -20,7 +21,7 @@ packet_data_base::~packet_data_base()
int packet_data_base::notify_progress(uint64_t total, uint64_t cur_size, uint32_t err)
{
if (progress_notify_)
progress_notify_(total, cur_size, err, user_data_);
return progress_notify_(total, cur_size, err, user_data_);
else
return ENOENT;
}
@ -148,11 +149,16 @@ file_saver::file_saver(void) : size_(0), wrote_(0), path_(""), check_(""), dst_(
{}
file_saver::~file_saver()
{
utils::to_log(LOG_LEVEL_DEBUG, "Write file(%s) over(%ld/%ld).\n", path_.c_str(), wrote_, size_);
close();
}
void file_saver::close(void)
{
if (map_)
map_->release();
map_ = nullptr;
if(dst_)
fclose(dst_);
dst_ = nullptr;
@ -161,17 +167,48 @@ void file_saver::close(void)
path_ = check_ = "";
}
int file_saver::open(const char* path, uint64_t size, const char* check)
int file_saver::set_verify_data(const char* data, size_t len)
{
if (data)
check_ = std::string(data, len);
else
check_ = "";
return 0;
}
int file_saver::open(const char* path, uint64_t size, bool in_mem, size_t off)
{
int err = 0;
close();
dst_ = fopen(path, "wb");
if(dst_)
wrote_ = off;
path_ = path;
size_ = size;
if (in_mem)
{
map_ = new file_map();
err = map_->open(path, size, false);
if (err || !map_->map())
{
map_->release();
map_ = nullptr;
}
else
return err;
}
err = utils::make_file_size(path, wrote_);
dst_ = fopen(path, "ab+");
if (dst_)
{
unsigned long long space = 0;
std::string dir(path);
size_t pos = dir.rfind(PATH_SEPARATOR[0]);
err = utils::get_disk_space(path, nullptr, &space, nullptr);
if (pos != std::string::npos)
dir.erase(pos);
err = utils::get_disk_space(dir.c_str(), nullptr, &space, nullptr);
if (err || space < size * 1.5)
{
fclose(dst_);
@ -180,12 +217,6 @@ int file_saver::open(const char* path, uint64_t size, const char* check)
if (err == 0)
err = ENOSPC;
}
else
{
path_ = path;
size_ = size;
check_ = check ? check : "";
}
}
else
{
@ -197,8 +228,22 @@ int file_saver::open(const char* path, uint64_t size, const char* check)
int file_saver::put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/)
{
if(!dst_)
if (!dst_)
{
if (map_)
{
// fix me: we consider whole file is all mapped in memory
int w = *size > size_ - wrote_ ? size_ - wrote_ : *size;
memcpy(map_->buffer() + wrote_, data, w);
*size = w;
wrote_ += w;
notify_progress(size_, wrote_, 0);
return 0;
}
return ENOENT;
}
int w = *size > size_ - wrote_ ? size_ - wrote_ : *size,
real_w = fwrite(data, 1, w, dst_), // should handle error here !
@ -229,9 +274,11 @@ uint32_t file_saver::get_required(void)
}
void file_saver::cancel(void)
{
std::string discard(path_);
utils::to_log(LOG_LEVEL_DEBUG, "Discard receiving file (%u/%u): '%s'.\n", wrote_, size_, path_.c_str());
close();
remove(path_.c_str());
remove(discard.c_str());
}
@ -401,12 +448,41 @@ file_reader::~file_reader()
{
if(src_)
fclose(src_);
if (map_)
map_->release();
utils::to_log(LOG_LEVEL_DEBUG, "Read file(%s) over(%ld/%ld).\n", path_.c_str(), consume_, len_);
}
int file_reader::open(const char* file)
int file_reader::open(const char* file, bool in_mem, size_t off)
{
if(src_)
fclose(src_);
src_ = nullptr;
consume_ = off;
if (in_mem)
{
map_ = new file_map();
if (map_->open(file, 0, true) || !map_->map())
{
map_->release();
map_ = nullptr;
}
else
{
if (map_->total_size() <= off)
{
map_->release();
map_ = nullptr;
return EOVERFLOW;
}
path_ = file;
len_ = map_->total_size();
return 0;
}
}
src_ = fopen(file, "rb");
if(!src_)
@ -414,9 +490,15 @@ int file_reader::open(const char* file)
FSEEK(src_, 0, SEEK_END);
len_ = FTELL(src_);
FSEEK(src_, 0, SEEK_SET);
FSEEK(src_, consume_, SEEK_SET);
path_ = file;
consume_ = 0;
if (len_ <= consume_)
{
fclose(src_);
src_ = nullptr;
return EOVERFLOW;
}
return 0;
}
@ -427,6 +509,11 @@ int file_reader::attach(FILE* f)
fclose(src_);
src_ = nullptr;
}
if (map_)
{
map_->release();
map_ = nullptr;
}
uint64_t cur = FTELL(f);
@ -455,7 +542,7 @@ FILE* file_reader::detach(void)
bool file_reader::is_memory_block(void)
{
return false;
return map_ != nullptr;
}
uint32_t file_reader::get_rest(void)
{
@ -465,14 +552,27 @@ uint32_t file_reader::get_rest(void)
// following API valid when is_memory_block() return true
uint8_t* file_reader::ptr(void)
{
return nullptr;
return map_ ? map_->buffer() : nullptr;
}
// following API valid when is_memory_block() return false
int file_reader::fetch_data(void* buf, uint32_t* size)
{
if (!src_)
{
if (map_)
{
if (*size + consume_ >= len_)
*size = len_ - consume_;
memcpy(buf, map_->buffer() + consume_, *size);
consume_ += *size;
notify_progress(len_, consume_, 0);
return 0;
}
return ENODATA;
}
size_t r = fread(buf, 1, *size, src_); // fix me if ERROR occurs !!!
@ -487,3 +587,200 @@ int file_reader::fetch_data(void* buf, uint32_t* size)
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
file_map::file_map()
{
utils::get_page_size(&os_map_size_);
}
file_map::~file_map()
{
close();
}
void file_map::unmap(void)
{
if (buf_)
#if OS_WIN
UnmapViewOfFile(buf_);
#else
munmap(buf_, map_size_);
#endif
buf_ = nullptr;
map_off_ = map_size_ = off_ = 0;
}
int file_map::open(const char* file, uint64_t size, bool readonly)
{
close();
std::string oper(readonly ? "open" : "create");
#if OS_WIN
HANDLE h = INVALID_HANDLE_VALUE;
DWORD access = PAGE_READONLY;
if (readonly)
{
h = CreateFileA(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
else
{
access = PAGE_READWRITE;
h = CreateFileA(file, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (h == INVALID_HANDLE_VALUE)
{
utils::to_log(LOG_LEVEL_WARNING, "FileMapping: %s '%s' failed: %d\n", oper.c_str(), file, GetLastError());
return EFAULT;
}
if (readonly)
{
DWORD* hi = (DWORD*)&size + 1,
* lo = (DWORD*)&size;
*lo = GetFileSize(h, hi);
}
else
{
LONG lo = size & 0x0ffffffff,
hi = size >> 32;
DWORD ret = SetFilePointer(h, lo, &hi, FILE_BEGIN);
if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
{
CloseHandle(h);
remove(file);
utils::to_log(LOG_LEVEL_WARNING, "FileMapping: no space(%ld) for '%s'.\n", size, file);
return ENOSPC;
}
else
{
// write a byte to ensure map success
SetFilePointer(h, -1, NULL, FILE_CURRENT);
lo = 0;
WriteFile(h, &lo, 1, &ret, NULL);
}
}
map_ = CreateFileMappingA(h, NULL, access, 0, 0, NULL);
access = GetLastError();
CloseHandle(h);
if (!map_)
{
remove(file);
map_ = INVALID_HANDLE_VALUE;
utils::to_log(LOG_LEVEL_WARNING, "FileMapping: create mapping object for '%s' failed: %d.\n", file, access);
return EFAULT;
}
#else
if (readonly)
map_ = (HANDLE)::open(file, O_RDONLY, 0644);
else
{
int err = utils::make_file_size(file, size);
if(err)
{
utils::to_log(LOG_LEVEL_FATAL, "FileMapping: make file(%s) size(%ld) = %d\n", file, size, err);
return err;
}
map_ = (HANDLE)::open(file, O_RDWR, 0666);
utils::to_log(LOG_LEVEL_DEBUG, "FileMapping: open('%s', O_APPEND, 0666) = %p\n", file, map_);
}
if (map_ == INVALID_HANDLE_VALUE)
{
int err = errno;
if(!readonly)
remove(file);
utils::to_log(LOG_LEVEL_WARNING, "FileMapping: create mapping object for '%s' failed: %d.\n", file, err);
return err;
}
#endif
path_file_ = file;
total_ = size;
read_only_ = readonly;
return 0;
}
int file_map::close(void)
{
unmap();
if (map_ != INVALID_HANDLE_VALUE)
#if OS_WIN
CloseHandle(map_);
#else
::close((int)(long)map_);
#endif
map_ = INVALID_HANDLE_VALUE;
total_ = 0;
return 0;
}
uint64_t file_map::total_size(void)
{
return total_;
}
uint8_t* file_map::map(uint64_t off, uint32_t* size)
{
uint32_t len = 0;
unmap();
if (!size)
size = &len;
if (off < total_)
{
DWORD hi = 0,
lo = 0,
cnt = 0;
map_off_ = off / os_map_size_ * os_map_size_;
off_ = off - map_off_;
hi = map_off_ >> 32;
lo = map_off_;
cnt = total_ - map_off_;
if (cnt - off > *size && *size)
{
cnt = ALIGN_TO(*size + off, os_map_size_);
if(cnt > total_ - map_off_)
cnt = total_ - map_off_;
}
map_size_ = cnt;
#if OS_WIN
buf_ = (uint8_t*)MapViewOfFile(map_, read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, hi, lo, map_size_);
#else
int priv = PROT_READ, prot = MAP_PRIVATE;
if (!read_only_)
{
priv |= PROT_WRITE;
prot = MAP_SHARED;
}
buf_ = (uint8_t*)mmap(nullptr, map_size_, priv, prot, (int)(long)map_, map_off_);
if(buf_ == INVALID_HANDLE_VALUE)
buf_ = nullptr;
#endif
if (!buf_)
{
utils::to_log(LOG_LEVEL_WARNING, "FileMapping: request map(%p + %u), real map(%p + %u) failed: %d\n"
, off, *size, map_off_, map_size_, GetLastError());
*size = 0;
}
else
*size = cnt - off;
}
return buf_ ? buf_ + off_ : nullptr;
}
uint8_t* file_map::buffer(void)
{
return buf_ ? buf_ + off_ : nullptr;
}

View File

@ -47,6 +47,35 @@ public:
void set_progress_notify(PROGRESS_NOTIFYER notify = PROGRESS_NOTIFYER(), void* param = nullptr);
};
class file_map : public refer
{
bool read_only_ = false; //
uint32_t os_map_size_ = 0; // desired mapping size of OS
uint64_t total_ = 0; // total size of the whole file
HANDLE map_ = INVALID_HANDLE_VALUE; // handle of the map-object
std::string path_file_; // local file
uint64_t map_off_ = 0; // offset in the file of current mapping buffer
uint32_t map_size_ = 0; // size of current mapping buffer
uint32_t off_ = 0; // offset to align to os_map_size_
uint8_t* buf_ = nullptr; // current mapping buffer
void unmap(void);
public:
file_map();
protected:
~file_map();
public:
int open(const char* file, uint64_t size, bool readonly);
int close(void);
uint64_t total_size(void);
uint8_t* map(uint64_t off = 0, uint32_t* size = 0); // size - in: desired size, 0 is from off to end; out: real size
uint8_t* buffer(void);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
/* data_holder, used when data is also required for a certain packet
@ -112,6 +141,7 @@ class file_saver : public data_holder
std::string path_;
std::string check_;
FILE *dst_;
file_map *map_ = nullptr;
uint32_t pack_cmd_;
uint32_t pack_id_;
@ -123,7 +153,8 @@ protected:
~file_saver();
public:
int open(const char* path, uint64_t size, const char* check = nullptr);
int set_verify_data(const char* data, size_t len);
int open(const char* path, uint64_t size, bool in_mem = false, size_t off = 0);
public:
virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) override;
@ -204,9 +235,10 @@ public:
class file_reader : public data_source
{
size_t len_;
size_t consume_;
FILE *src_;
size_t len_;
size_t consume_;
FILE *src_ = nullptr;
file_map *map_ = nullptr;
std::string path_;
public:
@ -216,7 +248,7 @@ protected:
~file_reader();
public:
int open(const char* file);
int open(const char* file, bool in_mem, size_t off = 0);
int attach(FILE* f);
FILE* detach(void);
@ -231,6 +263,7 @@ public:
virtual int fetch_data(void* buf, uint32_t* size) override;
};
CLS_PTR(packet_data_base);
CLS_PTR(data_holder);
CLS_PTR(mem_holder);
@ -251,7 +284,7 @@ CLS_PTR(file_reader);
//
// when invalid packet, suggest use the entire data
//
// packet_data_base_ptr* - return data_holder or data_source or nullptr <EFBFBD><EFBFBD>The number of bytes required for this packet, 0 is over for this packet<65><74>
// packet_data_base_ptr* - return data_holder or data_source or nullptr £¨The number of bytes required for this packet, 0 is over for this packet£©
//
// data_holder: the packet/command need more data than dyn_mem_ptr provides to complete the business. such as 'write a large file'
//

View File

@ -50,13 +50,13 @@ enum ep0_req
USB_REQ_EP0_SET_ENCRYPT, // 设置加密方式, req = me, ind = 0, val = 0, len = sizeof(PACK_BASE)
USB_REQ_EP0_SET_BULK_BUFFER, // 设置bulk缓冲区大小系数 req = me, ind = coef, val = 0, len = 0
};
enum bulk_status
enum woker_status
{
BULK_STATUS_NOT_START = 0, // has not initialized
BULK_STATUS_IDLE, // wait IO
BULK_STATUS_IO, // in reading or writing
BULK_STATUS_ERROR, // error occurs
BULK_STATUS_RESET, // in reset(close and reopen) process
WORKER_STATUS_NOT_START = 0, // has not start
WORKER_STATUS_IDLE, // idle
WORKER_STATUS_BUSY, // in working
WORKER_STATUS_ERROR, // error occurs
WORKER_STATUS_RESET, // in reset(close and reopen) process
};
enum packet_cmd

View File

@ -24,6 +24,7 @@
#if !OS_WIN // migrate codes from windows to linux ...
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <semaphore.h>
@ -97,6 +98,7 @@ typedef int BOOL;
#define USB_TIMEOUT_INFINITE 0
#define FSEEK fseek
#define FTELL ftell
#define INVALID_HANDLE_VALUE ((HANDLE)(-1))
extern DWORD GetLastError(void);
@ -104,8 +106,8 @@ extern DWORD GetPrivateProfileIntA(const char* app, const char* key, DWORD def,
extern DWORD GetPrivateProfileStringA(const char* app, const char* key, const char* init, char* buf, size_t len, const char* file);
extern void Sleep(DWORD milliseconds);
extern int GetModuleFileNameA(HMODULE module, char* buf, size_t len); // NOTE: parameter 'module' is consinder as a part of the module file name
extern int GetCurrentProcessId(void);
extern int GetCurrentThreadId(void);
extern uint64_t GetCurrentProcessId(void);
extern uint64_t GetCurrentThreadId(void);
#else
#include <Windows.h>

View File

@ -196,13 +196,13 @@ int GetModuleFileNameA(HMODULE module, char* buf, size_t len)
return len;
}
int GetCurrentThreadId(void)
uint64_t GetCurrentThreadId(void)
{
return pthread_self();
return (uint64_t)pthread_self();
}
int GetCurrentProcessId(void)
uint64_t GetCurrentProcessId(void)
{
return getpid();
return (uint64_t)getpid();
}
#endif
@ -236,7 +236,7 @@ class log_cls
}
else
{
std::string sep("\n\n===================================================================================================================\n");
std::string sep("\n\n========================================================================================================================\n");
fwrite(sep.c_str(), sizeof(sep[0]), sep.length(), file_);
}
@ -575,10 +575,18 @@ namespace utils
}
rv = fread(buf, 1, sizeof(buf) - 1, src);
}
if(rv == -1 && err)
{
*err = errno;
utils::to_log(LOG_LEVEL_DEBUG, "Failed to excute shell command '%s' in read pipe: %d - %s\n", cmd, errno, strerror(errno));
}
pclose(src);
}
else if(err)
{
*err = errno;
utils::to_log(LOG_LEVEL_DEBUG, "Failed to excute shell command '%s' in open pipe: %d - %s\n", cmd, errno, strerror(errno));
}
#endif
return std::move(result);
@ -978,6 +986,36 @@ namespace utils
{
return rename(from, to);
}
int make_file_size(const char* file, uint64_t size)
{
int err = 0;
get_command_result(("fallocate -l " + std::to_string(size) + " " + file).c_str(), -1, &err);
if(err == 0)
{
get_command_result(("truncate -s " + std::to_string(size) + " " + file).c_str(), -1, &err);
if(err == 0)
{
FILE* dst = fopen(file, "rb");
if(dst)
{
uint64_t rs = 0;
FSEEK(dst, 0, SEEK_END);
rs = FTELL(dst);
fclose(dst);
if(rs != size)
err = ENOSPC;
}
else
err = errno;
}
}
if(err)
remove(file);
return err;
}
int get_disk_space(const char* path, unsigned long long* total, unsigned long long* avail, unsigned long long* block)
{
@ -1049,7 +1087,7 @@ namespace utils
return ps;
}
void init_log(log_type type, log_level level, const char* fn_appendix)
std::string init_log(log_type type, log_level level, const char* fn_appendix)
{
std::string file("");
@ -1072,6 +1110,8 @@ namespace utils
log_cls::instance()->set_log_type(type, &file[0]);
log_cls::instance()->set_log_level(level);
return std::move(file);
}
void uninit(void)
{
@ -1872,22 +1912,22 @@ safe_thread::~safe_thread()
threads_.clear();
}
void safe_thread::thread_worker(std::function<void(void)> func, std::string name)
void safe_thread::thread_worker(std::function<void(void)> func, std::string name, void* addr)
{
try
{
utils::to_log(LOG_LEVEL_DEBUG, "+++ safe_thread of '%s' is running ...\n", name.c_str());
utils::to_log(LOG_LEVEL_DEBUG, "+++ safe_thread of '%s(%p) - %p' is running ...\n", name.c_str(), addr, GetCurrentThreadId());
func();
utils::to_log(LOG_LEVEL_DEBUG, "--- safe_thread of '%s' exited.\n", name.c_str());
utils::to_log(LOG_LEVEL_DEBUG, "--- safe_thread of '%s - %p' exited.\n", name.c_str(), GetCurrentThreadId());
return;
}
catch (std::exception e)
{
utils::to_log(LOG_LEVEL_FATAL, "Exception in thread '%s': %s\n", name.c_str(), e.what());
utils::to_log(LOG_LEVEL_FATAL, "Exception in thread '%p - %s': %s\n", GetCurrentThreadId(), name.c_str(), e.what());
}
catch (...)
{
utils::to_log(LOG_LEVEL_FATAL, "Unknown exception in thread '%s'!\n", name.c_str());
utils::to_log(LOG_LEVEL_FATAL, "Unknown exception in thread '%p - %s'!\n", GetCurrentThreadId(), name.c_str());
}
excep_que_.save(name, true);
}
@ -1908,12 +1948,12 @@ void safe_thread::set_exception_handler(std::function<void(const char*)> on_exce
{
excep_handler_ = on_exception;
}
int safe_thread::start(std::function<void(void)> f, const char* thread_name)
int safe_thread::start(std::function<void(void)> f, const char* thread_name, void* addr)
{
SAFETHRD st;
st.name = thread_name ? thread_name : "";
st.thread.reset(new std::thread(&safe_thread::thread_worker, this, f, thread_name));
st.thread.reset(new std::thread(&safe_thread::thread_worker, this, f, thread_name, addr));
{
SIMPLE_LOCK(lock_);

View File

@ -57,11 +57,13 @@ namespace utils
void set_ini_value(const char* seg, const char* key, const char* val, const char* cfg_file);
int enum_file(const char* folder, bool recursive, bool/*return false to stop enumeration*/(STDCALL* found)(const char* path_name, bool dir, void* param), void* param);
int move_file(const char* from, const char* to);
int make_file_size(const char* file, uint64_t size); // truncate or extend file size to 'size', create if not exist
int get_disk_space(const char* path, unsigned long long* total, unsigned long long* avail, unsigned long long* block);
unsigned int get_page_size(unsigned int* map_unit = nullptr);
void init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/);
// return logging file path if 'type' was LOG_TYPE_FILE
std::string init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/);
void uninit(void);
void log_info(const char* info, int level = LOG_LEVEL_ALL);
void log_mem_info(const char* desc, const void* data, size_t bytes, int level = LOG_LEVEL_ALL); // log as 0x12345678 00 01 02 ...
@ -354,7 +356,7 @@ class safe_thread
safe_fifo<std::string> excep_que_;
std::function<void(const char*)> excep_handler_ = std::function<void(const char*)>();
void thread_worker(std::function<void(void)> func, std::string name);
void thread_worker(std::function<void(void)> func, std::string name, void* addr);
void thread_notify_exception(void);
public:
@ -363,6 +365,6 @@ public:
public:
void set_exception_handler(std::function<void(const char*)> on_exception = std::function<void(const char*)>());
int start(std::function<void(void)> f, const char* thread_name);
int start(std::function<void(void)> f, const char* thread_name, void* addr = nullptr);
int stop(const char* thread_name);
};

View File

@ -1158,13 +1158,42 @@ void device_option::insert_option(gb_json* opt, sane_opt_provider* from, const c
}
else
{
int index = -1;
int index = -1, pos = -1;
if (group)
index = insert_group(group, group);
index = next_group(index + 1);
// insert poisition according to 'ui-pos'
if (!opt->get_value("ui-pos", pos) || pos == -1)
{
index = next_group(index + 1);
}
else
{
for (index++; index < origin_->children(); ++index)
{
gb_json* sib = origin_->child(index);
std::string t("");
int sit = -1;
if (!sib->get_value("type", t) || t == JSON_SANE_TYPE_GROUP)
{
sib->release();
break;
}
if (!sib->get_value("ui-pos", sit) || sit == -1)
{
sib->release();
break;
}
sib->release();
if (pos < sit)
break;
}
}
origin_->insert(index, opt->key().c_str(), opt);
src_[opt->key()] = from;
from->add_ref();
}
@ -1310,7 +1339,24 @@ gb_json* device_option::copy_opt(gb_json* from)
// 2: enabled ...
if (slaver_.count(to->key()))
to->set_value("enabled", slaver_[to->key()]->value(&device_option::calc_simple_logic_expression, this));
{
bool enable = slaver_[to->key()]->value(&device_option::calc_simple_logic_expression, this);
to->set_value("enabled", enable);
if (src_.count(to->key()))
{
src_[to->key()]->enable(to->key().c_str(), enable);
sane_opt_provider* next = src_[to->key()]->get_following(to->key().c_str());
while (next)
{
next->enable(to->key().c_str(), enable);
sane_opt_provider* next1 = next->get_following(to->key().c_str());
next->release();
next = next1;
}
}
}
// 3: default value ...
if (init_value_.count(to->key()))

View File

@ -688,6 +688,25 @@ int usb_device::close_device(void)
}
int usb_device::pull_up(std::string* msg)
{
{
int dst = open(udc_.c_str(), O_RDWR);
if(dst == -1)
utils::to_log(LOG_LEVEL_DEBUG, "Try write '%s' to '%s' failed(open): %s\n", dwc3_.c_str(), udc_.c_str(), strerror(errno));
else
{
int l = write(dst, dwc3_.c_str(), dwc3_.length()),
err = errno;
close(dst);
if(l == dwc3_.length())
{
utils::to_log(LOG_LEVEL_DEBUG, "pull up device by write '%s' to '%s' directly success.\n", dwc3_.c_str(), udc_.c_str());
return 0;
}
else
utils::to_log(LOG_LEVEL_DEBUG, "Try write '%s' to '%s' failed(write): %s\n", dwc3_.c_str(), udc_.c_str(), strerror(errno));
}
}
std::string cmd("echo " + pwd_ + " | sudo -S sh -c \"echo " + dwc3_ + " > " + udc_ + "\"");
int err = 0;
std::string info(utils::get_command_result(cmd.c_str(), -1, &err));

View File

@ -21,7 +21,8 @@ async_usb_gadget::async_usb_gadget(std::function<FUNCTION_PROTO_COMMAND_HANDLE>
, cmd_que_("in-queue"), sent_que_("out-queue")
, wait_in_("wait_usb_enable_in"), wait_out_("wait_usb_enable_out")
{
memset((void*)&status_, 0, sizeof(status_));
cmd_que_.enable_wait_log(false);
sent_que_.enable_wait_log(false);
dev_ = new usb_device("fe900000.dwc3", "/opt/cfg/usb_gadget/g1/UDC", "linaro");
dev_->add_endpoint(USB_EP_BULK_IN, true, true);
@ -87,10 +88,10 @@ async_usb_gadget::async_usb_gadget(std::function<FUNCTION_PROTO_COMMAND_HANDLE>
threads_.set_exception_handler(excep);
unit_in_ = unit_out_ = dev_->get_max_packet();
threads_.start(task, "thread_pump_task");
threads_.start(bulkw, "thread_read_bulk");
threads_.start(bulkr, "thread_write_bulk");
threads_.start(ep0, "thread_read_ep0");
threads_.start(task, "thread_pump_task", (void*)&async_usb_gadget::thread_pump_task);
threads_.start(bulkw, "thread_write_bulk", (void*)&async_usb_gadget::thread_write_bulk);
threads_.start(bulkr, "thread_read_bulk", (void*)&async_usb_gadget::thread_read_bulk);
threads_.start(ep0, "thread_read_ep0", (void*)&async_usb_gadget::thread_read_ep0);
}
async_usb_gadget::~async_usb_gadget()
@ -149,19 +150,19 @@ dyn_mem_ptr async_usb_gadget::handle_ctrl_message(dyn_mem_ptr data)
switch (pev->type)
{
case FUNCTIONFS_ENABLE:
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS ENABLE\n");
online_ = true;
session_id_++;
utils::to_log(LOG_LEVEL_DEBUG, "////////////// EP0 FFS ENABLE, start session %u ...\n", session_id_);
online_ = true;
wait_in_.trigger();
wait_out_.trigger();
if(dev_connect_)
dev_connect_(true);
dev_connect_(online_);
break;
case FUNCTIONFS_DISABLE:
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS DISABLE\n");
online_ = false;
if(dev_connect_)
dev_connect_(false);
dev_connect_(online_);
utils::to_log(LOG_LEVEL_DEBUG, "////////////// EP0 FFS DISABLE, end session %u ...\n\n", session_id_);
break;
case FUNCTIONFS_SETUP:
reply = handle_ctrl_setup(data);
@ -219,8 +220,17 @@ dyn_mem_ptr async_usb_gadget::handle_ctrl_setup(dyn_mem_ptr data)
break;
case USB_REQ_EP0_GET_STATUS:
reply = dyn_mem::memory(sizeof(struct _ep0_reply));
reply->set_len(sizeof(struct _ep0_reply));
{
reply->put((void*)&status_, sizeof(status_));
LPEP0REPLYSTATUS lps = (LPEP0REPLYSTATUS)reply->ptr();
lps->in_status = statu_in_;
lps->out_status = statu_out_;
lps->task_cmd = task_cmd_;
lps->task_pack_id = task_packet_id_;
lps->task_required_bytes = want_bytes_task_;
lps->packets_to_sent = sent_que_.size();
lps->bytes_to_sent = want_bytes_in_;
utils::log_mem_info("threads status:", lps, sizeof(*lps), LOG_LEVEL_DEBUG);
}
break;
case USB_REQ_EP0_RESET_BULK:
@ -255,6 +265,8 @@ dyn_mem_ptr async_usb_gadget::handle_ctrl_setup(dyn_mem_ptr data)
utils::to_log(LOG_LEVEL_ALL, "EP0 event(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) has not handled by user business.\n"
, pev->u.setup.bRequestType, pev->u.setup.bRequest, pev->u.setup.wValue, pev->u.setup.wIndex, pev->u.setup.wLength);
}
if(reply)
reply->set_session_id(data->get_session_id());
return reply;
}
@ -264,13 +276,16 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err)
size_t bulk_size = unit_in_ * get_buf_coefficient(),
total = data->get_rest(), off = 0, size = total > bulk_size ? bulk_size : total;
int w = 0;
bool fail = false;
statu_in_ = WORKER_STATUS_BUSY;
want_bytes_in_ = total;
if(data->is_memory_block())
{
while((w = write(fd, ptr + off, size)) > 0)
{
off += w;
status_.bytes_to_sent -= w;
want_bytes_in_ -= w;
if(off >= total)
break;
if(off + bulk_size < total)
@ -279,7 +294,10 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err)
size = total - off;
}
if(w <= 0 && err)
{
*err = errno;
}
fail = w <= 0;
}
else
{
@ -296,7 +314,7 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err)
w = write(fd, ptr + off, len);
while(w > 0 && w + off < len)
{
status_.bytes_to_sent -= w;
want_bytes_in_ -= w;
total += w;
off += w;
w = write(fd, ptr + off, len - off);
@ -304,14 +322,14 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err)
if(w <= 0)
{
fail = true;
if(err)
*err = errno;
utils::to_log(LOG_LEVEL_ALL, "inner_write_bulk error(%d/%d): %d (%s)\n", off, len, errno, strerror(errno));
break;
}
else
{
status_.bytes_to_sent -= w;
want_bytes_in_ -= w;
total += w;
}
@ -322,6 +340,8 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err)
buf->release();
off = total;
}
statu_in_ = fail ? WORKER_STATUS_ERROR : WORKER_STATUS_IDLE;
want_bytes_in_ = 0;
return off;
}
@ -358,7 +378,6 @@ void async_usb_gadget::thread_read_ep0(void)
std::string msg("");
struct usb_functionfs_event* pe = (struct usb_functionfs_event*)ptr;
utils::to_log(LOG_LEVEL_ALL, "EP0 monitoring thread(%p of id %lx) started ...\n", &async_usb_gadget::thread_read_ep0, getpid());
ret = dev_->pull_up(&msg);
while(run_)
{
@ -424,17 +443,17 @@ void async_usb_gadget::thread_read_bulk(int fd)
dyn_mem_ptr buf(dyn_mem::memory(bulk_size));
int l = 0;
status_.out_status = BULK_STATUS_IO;
statu_out_ = WORKER_STATUS_BUSY;
buf->set_session_id(session_id_);
l = read(fd, buf->ptr(), bulk_size);
statu_out_ = WORKER_STATUS_IDLE;
if(l <= 0)
{
buf->release();
if(errno)
{
utils::to_log(LOG_LEVEL_ALL, "read bulk(%d) failed: %d(%s)\n", l, errno, strerror(errno));
status_.out_status = BULK_STATUS_ERROR;
status_.out_err = errno;
statu_out_ = WORKER_STATUS_ERROR;
break;
}
else
@ -446,22 +465,19 @@ void async_usb_gadget::thread_read_bulk(int fd)
{
utils::to_log(LOG_LEVEL_ALL, "thread_read_bulk do reset-bulk ...\n");
buf->release();
if(!run_)
break;
break;
}
else
{
status_.out_status = BULK_STATUS_IDLE;
buf->set_len(l);
cmd_que_.save(buf, true);
}
}
if(status_.out_status == BULK_STATUS_IDLE)
status_.out_status = BULK_STATUS_NOT_START;
statu_out_ = WORKER_STATUS_NOT_START;
}
void async_usb_gadget::thread_write_bulk(int fd)
{
status_.in_status = BULK_STATUS_IDLE;
statu_in_ = WORKER_STATUS_IDLE;
while(run_)
{
data_source_ptr data;
@ -469,24 +485,17 @@ void async_usb_gadget::thread_write_bulk(int fd)
if(sent_que_.take(data, true))
{
status_.packets_to_sent = sent_que_.size();
status_.bytes_to_sent = data->get_rest();
status_.in_status = BULK_STATUS_IO;
want_bytes_in_ = data->get_rest();
inner_write_bulk(fd, data, &err);
status_.in_status = BULK_STATUS_IDLE;
status_.bytes_to_sent = 0;
data->release();
if(err)
{
utils::to_log(LOG_LEVEL_ALL, "write bulk failed: %d(%s)\n", errno, strerror(errno));
status_.in_status = BULK_STATUS_ERROR;
status_.in_err = err;
break;
}
}
}
if(status_.in_status == BULK_STATUS_IDLE)
status_.in_status = BULK_STATUS_NOT_START;
statu_in_ = WORKER_STATUS_NOT_START;
}
void async_usb_gadget::thread_pump_task(void)
{
@ -500,11 +509,12 @@ void async_usb_gadget::thread_pump_task(void)
while(run_)
{
data = nullptr;
statu_task_ = WORKER_STATUS_IDLE;
if(cmd_que_.take(data, true) && data)
{
status_.task_cnt = cmd_que_.size();
if(max_que < status_.task_cnt)
max_que = status_.task_cnt;
statu_task_ = WORKER_STATUS_BUSY;
if(max_que < cmd_que_.size())
max_que = cmd_que_.size();
if(prev)
{
@ -549,8 +559,9 @@ void async_usb_gadget::thread_pump_task(void)
else
{
pack = (LPPACK_BASE)data->ptr();
status_.task_cmd = pack->cmd;
status_.task_pack_id = pack->pack_id;
task_cmd_ = pack->cmd;
task_packet_id_ = pack->pack_id;
want_bytes_task_ = 0;
used = data->get_rest();
reply = handle_bulk_command(data, &used, &pack_data);
notify_reply_ok = used & (INT32_MAX + 1);
@ -564,9 +575,14 @@ void async_usb_gadget::thread_pump_task(void)
ds = dynamic_cast<data_source_ptr>(pack_data);
if(!ds)
pack_data->release();
else
want_bytes_task_ = ds->get_rest();
}
else
{
total_size = 0;
want_bytes_task_ = dh->get_required();
}
}
}
}
@ -588,10 +604,15 @@ void async_usb_gadget::thread_pump_task(void)
BASE_PACKET_REPLY(*pack, dh->get_packet_command() + 1, dh->get_packet_id(), err);
reply->set_len(sizeof(PACK_BASE));
utils::to_log(LOG_LEVEL_ALL, "Finished receiving file with error(Max queue size is %u): %d, total size = 0x%x\n", max_que, err, total_size);
utils::to_log(LOG_LEVEL_ALL, "Finished receiving large data with error(Max queue size is %u): %d, total size = 0x%x\n", max_que, err, total_size);
dh->release();
dh = nullptr;
want_bytes_task_ = 0;
}
else
{
want_bytes_task_ = dh->get_required();
}
used = len;
@ -612,7 +633,7 @@ void async_usb_gadget::thread_pump_task(void)
reply->release();
reply = enc;
}
reply->set_session_id(data->get_session_id());
write_bulk(dynamic_cast<data_source_ptr>(reply));
if(notify_reply_ok)
handle_bulk_command(data, nullptr, nullptr);
@ -628,17 +649,19 @@ void async_usb_gadget::thread_pump_task(void)
ds = nullptr;
}
status_.task_required_bytes = dh ? dh->get_required() : 0;
if(status_.task_required_bytes == 0)
status_.task_cmd = status_.task_pack_id = 0;
data->used(used);
}while(used && data->get_rest());
if(data->get_rest())
prev = data;
else
{
if(!dh)
{
task_cmd_ = task_packet_id_ = want_bytes_task_ = 0;
}
data->release();
}
}
}
if(prev)
@ -674,7 +697,7 @@ int async_usb_gadget::write_bulk(data_source_ptr data)
{
if(data->get_session_id() != session_id_ || !online_)
{
utils::to_log(LOG_LEVEL_DEBUG, "Discard packet for the session ID(%u) is not equal current session(%u) or is offline.\n", data->get_session_id(), session_id_);
utils::to_log(LOG_LEVEL_DEBUG, "Discard reply packet for the session ID(%u) is not equal current session(%u) or is offline.\n", data->get_session_id(), session_id_);
data->release();
return sent_que_.size();
@ -692,4 +715,4 @@ int async_usb_gadget::write_bulk(data_source_ptr data)
int async_usb_gadget::last_error(void)
{
return last_err_;
}
}

View File

@ -59,7 +59,16 @@ class async_usb_gadget : public refer
uint8_t enc_data_;
int last_err_ = 0;
volatile EP0REPLYSTATUS status_;
uint8_t statu_in_ = WORKER_STATUS_NOT_START;
uint32_t want_bytes_in_ = 0;
uint8_t statu_out_ = WORKER_STATUS_NOT_START;
uint8_t statu_task_ = WORKER_STATUS_NOT_START;
uint32_t want_bytes_task_ = 0;
uint32_t task_cmd_ = 0;
uint32_t task_packet_id_ = 0;
safe_fifo<dyn_mem_ptr> cmd_que_;
safe_fifo<data_source_ptr> sent_que_;