1. -run 脚本模式完善
- shebang 脚本 (#!/usr/bin/env pcc -run) 支持
- -rstdin 自定义输入、argv 参数传递
- win32/pcc-run.cmd 便捷启动器
2. -O2 优化等级
- -O0/-O1/-O2/-O3/-Os 全等级验证
- __OPTIMIZE__ 宏正确设置,常量折叠生效
3. C17 全特性
- 默认标准改为 C11 (__STDC_VERSION__=201112L)
- 新增 -std=c17/c18/c99/c89 支持
- _Generic/_Atomic/_Alignas/匿名结构/TLS 全通过
4. pcmake 构建工具 (tools/)
- 纯 C 编写,用 pcc 自身编译
- pcmake.conf 配置: sources/include/libs/output/flags
- CreateProcess 正确处理带空格路径
- pcmake.bat 一键构建 + clean
- 示例: examples/demo 多文件项目
5. 多线程库封装
- win32/include/pthread.h: POSIX 线程 Windows 实现
(CreateThread 封装, 事件驱动条件变量, 惰性初始化互斥锁)
- win32/include/threads.h: C11 标准线程 <threads.h>
- 4线程并发/互斥/条件变量/生产者消费者 测试通过
308 行
7.1 KiB
C
308 行
7.1 KiB
C
/*
|
|
* pthread.h - POSIX threads for Windows (PCC)
|
|
*
|
|
* A lightweight pthread implementation on top of Win32
|
|
* thread APIs. Provides the commonly used subset of POSIX
|
|
* threads sufficient for most C programs.
|
|
*
|
|
* Condition variables are implemented with Win32 events,
|
|
* so no modern kernel32 APIs are required.
|
|
*
|
|
* License: MIT
|
|
*/
|
|
|
|
#ifndef _PCC_PTHREAD_H
|
|
#define _PCC_PTHREAD_H
|
|
|
|
#include <windows.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* ---------- types ---------- */
|
|
|
|
typedef HANDLE pthread_t;
|
|
typedef DWORD pthread_attr_t;
|
|
|
|
typedef struct {
|
|
CRITICAL_SECTION cs;
|
|
} pthread_mutex_t;
|
|
|
|
typedef struct {
|
|
int dummy;
|
|
} pthread_mutexattr_t;
|
|
|
|
typedef struct {
|
|
HANDLE event; /* auto-reset event used for signaling */
|
|
CRITICAL_SECTION cs; /* protects waiters count */
|
|
int waiters;
|
|
} pthread_cond_t;
|
|
|
|
typedef struct {
|
|
int dummy;
|
|
} pthread_condattr_t;
|
|
|
|
typedef struct {
|
|
int done;
|
|
} pthread_once_control_t;
|
|
|
|
#define PTHREAD_ONCE_INIT { 0 }
|
|
/* Zero-init is valid for our event-based cond; for mutex we
|
|
lazily initialize the CRITICAL_SECTION on first use. */
|
|
#define PTHREAD_MUTEX_INITIALIZER { { 0 } }
|
|
#define PTHREAD_COND_INITIALIZER { NULL, { 0 }, 0 }
|
|
|
|
typedef DWORD pthread_key_t;
|
|
|
|
/* ---------- thread creation ---------- */
|
|
|
|
static DWORD WINAPI pthread_wrapper(LPVOID arg)
|
|
{
|
|
void *(*fn)(void *) = ((void **)arg)[0];
|
|
void *data = ((void **)arg)[1];
|
|
void *result;
|
|
free(arg);
|
|
result = fn(data);
|
|
/* return value stored in thread exit code */
|
|
return (DWORD)(uintptr_t)result;
|
|
}
|
|
|
|
static int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
|
void *(*start_routine)(void *), void *arg)
|
|
{
|
|
void **box = (void **)malloc(2 * sizeof(void *));
|
|
DWORD tid;
|
|
HANDLE h;
|
|
(void)attr;
|
|
if (!box) return -1;
|
|
box[0] = (void *)start_routine;
|
|
box[1] = arg;
|
|
h = CreateThread(NULL, 0, pthread_wrapper, box, 0, &tid);
|
|
if (!h) {
|
|
free(box);
|
|
return -1;
|
|
}
|
|
*thread = h;
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_join(pthread_t thread, void **retval)
|
|
{
|
|
DWORD code = 0;
|
|
if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
|
|
return -1;
|
|
GetExitCodeThread(thread, &code);
|
|
CloseHandle(thread);
|
|
if (retval)
|
|
*retval = (void *)(uintptr_t)code;
|
|
return 0;
|
|
}
|
|
|
|
static pthread_t pthread_self(void)
|
|
{
|
|
return GetCurrentThread();
|
|
}
|
|
|
|
static int pthread_equal(pthread_t t1, pthread_t t2)
|
|
{
|
|
return t1 == t2;
|
|
}
|
|
|
|
static void pthread_exit(void *retval)
|
|
{
|
|
ExitThread((DWORD)(uintptr_t)retval);
|
|
}
|
|
|
|
static int pthread_detach(pthread_t thread)
|
|
{
|
|
CloseHandle(thread);
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- mutex (with lazy init for static initializers) ---------- */
|
|
|
|
static void pthread_mutex_ensure(pthread_mutex_t *m)
|
|
{
|
|
/* CRITICAL_SECTION is initialized when DebugInfo != NULL */
|
|
if (m->cs.DebugInfo == NULL)
|
|
InitializeCriticalSection(&m->cs);
|
|
}
|
|
|
|
static int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a)
|
|
{
|
|
(void)a;
|
|
memset(&m->cs, 0, sizeof m->cs);
|
|
InitializeCriticalSection(&m->cs);
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_mutex_destroy(pthread_mutex_t *m)
|
|
{
|
|
if (m->cs.DebugInfo)
|
|
DeleteCriticalSection(&m->cs);
|
|
memset(&m->cs, 0, sizeof m->cs);
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_mutex_lock(pthread_mutex_t *m)
|
|
{
|
|
pthread_mutex_ensure(m);
|
|
EnterCriticalSection(&m->cs);
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_mutex_trylock(pthread_mutex_t *m)
|
|
{
|
|
pthread_mutex_ensure(m);
|
|
return TryEnterCriticalSection(&m->cs) ? 0 : 1;
|
|
}
|
|
|
|
static int pthread_mutex_unlock(pthread_mutex_t *m)
|
|
{
|
|
LeaveCriticalSection(&m->cs);
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- condition variable (event-based) ---------- */
|
|
|
|
static int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
|
|
{
|
|
(void)a;
|
|
c->event = CreateEventA(NULL, FALSE, FALSE, NULL); /* auto-reset */
|
|
if (!c->event) return -1;
|
|
InitializeCriticalSection(&c->cs);
|
|
c->waiters = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_cond_destroy(pthread_cond_t *c)
|
|
{
|
|
if (c->event) CloseHandle(c->event);
|
|
DeleteCriticalSection(&c->cs);
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
|
|
{
|
|
EnterCriticalSection(&c->cs);
|
|
c->waiters++;
|
|
LeaveCriticalSection(&c->cs);
|
|
|
|
LeaveCriticalSection(&m->cs);
|
|
/* wait for signal; spurious wakeups possible, caller must re-check */
|
|
WaitForSingleObject(c->event, INFINITE);
|
|
EnterCriticalSection(&m->cs);
|
|
|
|
EnterCriticalSection(&c->cs);
|
|
if (c->waiters > 0) c->waiters--;
|
|
LeaveCriticalSection(&c->cs);
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m,
|
|
const struct timespec *abstime)
|
|
{
|
|
DWORD ms = INFINITE;
|
|
if (abstime) {
|
|
FILETIME ft;
|
|
ULARGE_INTEGER ul;
|
|
unsigned __int64 target, now;
|
|
GetSystemTimeAsFileTime(&ft);
|
|
ul.LowPart = ft.dwLowDateTime;
|
|
ul.HighPart = ft.dwHighDateTime;
|
|
now = ul.QuadPart; /* 100ns since 1601 */
|
|
target = ((unsigned __int64)abstime->tv_sec + 11644473600ULL)
|
|
* 10000000ULL + abstime->tv_nsec / 100;
|
|
if (target <= now)
|
|
return 110; /* ETIMEDOUT */
|
|
ms = (DWORD)((target - now) / 10000);
|
|
}
|
|
|
|
EnterCriticalSection(&c->cs);
|
|
c->waiters++;
|
|
LeaveCriticalSection(&c->cs);
|
|
|
|
LeaveCriticalSection(&m->cs);
|
|
{
|
|
DWORD r = WaitForSingleObject(c->event, ms);
|
|
EnterCriticalSection(&m->cs);
|
|
EnterCriticalSection(&c->cs);
|
|
if (c->waiters > 0) c->waiters--;
|
|
LeaveCriticalSection(&c->cs);
|
|
if (r == WAIT_TIMEOUT) return 110;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_cond_signal(pthread_cond_t *c)
|
|
{
|
|
EnterCriticalSection(&c->cs);
|
|
if (c->waiters > 0)
|
|
SetEvent(c->event);
|
|
LeaveCriticalSection(&c->cs);
|
|
return 0;
|
|
}
|
|
|
|
static int pthread_cond_broadcast(pthread_cond_t *c)
|
|
{
|
|
int n;
|
|
EnterCriticalSection(&c->cs);
|
|
n = c->waiters;
|
|
LeaveCriticalSection(&c->cs);
|
|
/* set event multiple times; auto-reset wakes one waiter per set */
|
|
while (n-- > 0)
|
|
SetEvent(c->event);
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- once ---------- */
|
|
|
|
static int pthread_once(pthread_once_control_t *once,
|
|
void (*init_routine)(void))
|
|
{
|
|
if (!once->done) {
|
|
once->done = 1;
|
|
init_routine();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- keys (TLS) ---------- */
|
|
|
|
static int pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
|
|
{
|
|
(void)destructor;
|
|
*key = TlsAlloc();
|
|
return (*key == TLS_OUT_OF_INDEXES) ? -1 : 0;
|
|
}
|
|
|
|
static int pthread_key_delete(pthread_key_t key)
|
|
{
|
|
return TlsFree(key) ? 0 : -1;
|
|
}
|
|
|
|
static void *pthread_getspecific(pthread_key_t key)
|
|
{
|
|
return TlsGetValue(key);
|
|
}
|
|
|
|
static int pthread_setspecific(pthread_key_t key, const void *value)
|
|
{
|
|
return TlsSetValue(key, (LPVOID)value) ? 0 : -1;
|
|
}
|
|
|
|
/* ---------- attributes (minimal) ---------- */
|
|
|
|
static int pthread_attr_init(pthread_attr_t *a) { (void)a; return 0; }
|
|
static int pthread_attr_destroy(pthread_attr_t *a) { (void)a; return 0; }
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* _PCC_PTHREAD_H */
|