264 lines
6.6 KiB
C
264 lines
6.6 KiB
C
#define _POSIX_C_SOURCE 200112L
|
||
#include "log.h"
|
||
#include <stdio.h>
|
||
#include <stddef.h>
|
||
#include <stdlib.h>
|
||
#include <unistd.h>
|
||
#include <time.h>
|
||
#include <errno.h>
|
||
#include <fcntl.h>
|
||
#include <string.h>
|
||
|
||
int in_log(logs *log,log_manager *self)
|
||
{
|
||
if(log == NULL||self == NULL)
|
||
return -1;
|
||
log->log[MAX_LOG_LENGTH-1] = '\0';
|
||
sem_wait(&self->log_sem);//加锁
|
||
if(self->log == NULL){
|
||
self->log = log;
|
||
self->rear = log;
|
||
self->count++;
|
||
sem_post(&self->log_sem);
|
||
return self->count;
|
||
}
|
||
if(self->count == 1)
|
||
self->log->next = log;
|
||
self->count++;
|
||
log->next = NULL;
|
||
self->rear->next = log;
|
||
self->rear = log;
|
||
sem_post(&self->log_sem);
|
||
return self->count;
|
||
}
|
||
|
||
logs *out_log(log_manager *self)
|
||
{
|
||
if(self == NULL)
|
||
return NULL;
|
||
sem_wait(&self->log_sem);
|
||
logs *buf = self->log;
|
||
if(buf==NULL)
|
||
{
|
||
sem_post(&self->log_sem);
|
||
return NULL;
|
||
}
|
||
if(self->log->next ==NULL)
|
||
self->log = self->rear = NULL;
|
||
else
|
||
self->log = self->log->next;
|
||
self->count--;
|
||
sem_post(&self->log_sem);
|
||
buf->next =NULL;
|
||
return buf;
|
||
}
|
||
|
||
int sleep_with_signal(log_manager *self)
|
||
{
|
||
struct timespec ts;
|
||
int rc;
|
||
|
||
/* 计算绝对超时:当前 + 1000 s */
|
||
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
|
||
return -1; /* 罕见失败 */
|
||
|
||
ts.tv_sec += 1000;
|
||
/* 纳秒部分无需处理,1000 s 整不会溢出 */
|
||
|
||
pthread_mutex_lock(&self->mtx); /* 进入临界区 */
|
||
|
||
while (1) {
|
||
rc = pthread_cond_timedwait(&self->cond, &self->mtx, &ts);
|
||
if (rc == ETIMEDOUT) { /* 1000 s 到点 */
|
||
pthread_mutex_unlock(&self->mtx);
|
||
return 1; /* 正常超时 */
|
||
}
|
||
if (rc != 0) { /* 其他错误 */
|
||
pthread_mutex_unlock(&self->mtx);
|
||
return -1;
|
||
}
|
||
|
||
/* 被 signal / broadcast 提前唤醒,检查 stop */
|
||
if (self->stop == 1) {/* 主线程要求退出 */
|
||
pthread_mutex_unlock(&self->mtx);
|
||
return 0; /* 告诉调用者:该结束了 */
|
||
}
|
||
}
|
||
}
|
||
|
||
int cleanup(log_manager *self)
|
||
{
|
||
if(self->log ==NULL)
|
||
return 1;
|
||
logs *tobeclean,*loc;
|
||
sem_wait(&self->log_sem);//获取信号量
|
||
loc = self->log;
|
||
self->log = NULL;
|
||
self->count = 0;//摘取log链
|
||
sem_post(&self->log_sem);
|
||
//释放信号量
|
||
char *logbuf;
|
||
void *logbufbk;
|
||
char failback[MAX_LOG_LENGTH];
|
||
logbuf = (char*)malloc(1);
|
||
logbuf[0] = '\0';
|
||
size_t buf_length,buf_lengthbk = 0;
|
||
int fd;
|
||
while(loc->next !=NULL)
|
||
{
|
||
tobeclean = loc;
|
||
loc = loc->next;
|
||
if(logbuf != failback){
|
||
logbufbk = logbuf;
|
||
logbuf = (char*)realloc(logbuf,strlen(logbuf)+strlen(tobeclean->log)+1);//为日志分配新的内存
|
||
}
|
||
if(logbuf == NULL){
|
||
fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND, 0644);
|
||
if(fd != -1)
|
||
{
|
||
write(fd,logbufbk,buf_length);
|
||
close(fd);
|
||
}
|
||
free(logbufbk);
|
||
logbuf = failback;//降级策略,堆空间不足时,使用预分配栈空间,保留最后一条日志
|
||
}
|
||
if(logbuf != failback){
|
||
buf_lengthbk = buf_length;
|
||
buf_length = strlen(logbuf)+strlen(tobeclean->log);
|
||
strcpy(logbuf+buf_lengthbk,tobeclean->log);
|
||
}
|
||
else
|
||
{
|
||
buf_length = MAX_LOG_LENGTH;
|
||
}
|
||
free(tobeclean);
|
||
}
|
||
if(logbuf != failback){
|
||
logbufbk = logbuf;
|
||
logbuf = (char*)realloc(logbuf,strlen(logbuf)+strlen(loc->log)+2);
|
||
if(logbuf == NULL)
|
||
{
|
||
free(logbufbk);
|
||
logbuf = failback;
|
||
strcpy(logbuf,loc->log);
|
||
buf_length = strlen(loc->log);
|
||
|
||
}
|
||
else{
|
||
buf_lengthbk = buf_length;
|
||
buf_length = strlen(logbuf)+strlen(loc->log);
|
||
strcpy(logbuf+buf_lengthbk,loc->log);
|
||
}
|
||
}
|
||
else{
|
||
strcpy(logbuf,loc->log);
|
||
buf_length = strlen(logbuf);
|
||
}
|
||
if(logbuf == failback&&buf_length>MAX_LOG_LENGTH)
|
||
logbuf[MAX_LOG_LENGTH-1] = '\0';
|
||
else{
|
||
logbuf[buf_length] = '\0';
|
||
}
|
||
free(loc);
|
||
|
||
fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND, 0644);
|
||
if(fd == -1){
|
||
perror("file:");
|
||
if(logbuf != failback)
|
||
free(logbuf);
|
||
return -1;
|
||
}
|
||
int error_buf = write(fd,logbuf,strlen(logbuf));
|
||
if(error_buf==-1){
|
||
close(fd);
|
||
if(logbuf != failback)
|
||
free(logbuf);
|
||
return -1;
|
||
}
|
||
else if(error_buf<buf_length)
|
||
write(fd,"unknown error case log write cut down\n",38);
|
||
if(logbuf != failback)
|
||
free(logbuf);
|
||
close(fd);
|
||
return 0;
|
||
}
|
||
|
||
void log_manager_stop(log_manager *self)
|
||
{
|
||
pthread_mutex_lock(&self->mtx);
|
||
if(self->stop == 1){
|
||
pthread_mutex_unlock(&self->mtx);
|
||
return ;
|
||
}
|
||
self->stop = 1;
|
||
/* 置退出标志 */
|
||
printf("SYS:stopping loger\n");
|
||
logs *log = malloc(sizeof(logs));
|
||
strcpy(log->log,"SYS:stopping loger\n");
|
||
self->in_log(log,self);
|
||
log = malloc(sizeof(logs));
|
||
strcpy(log->log,"SYS:done\n");
|
||
printf("SYS:done\n");
|
||
self->in_log(log,self);
|
||
pthread_mutex_unlock(&self->mtx);
|
||
pthread_cond_broadcast(&self->cond); /* 唤醒所有等待线程 */
|
||
}
|
||
|
||
//定期清理函数
|
||
void *clear_log(void *self_p)
|
||
{
|
||
log_manager *self = (log_manager*)self_p;
|
||
for(;;)
|
||
{
|
||
sleep_with_signal(self);
|
||
sem_wait(&self->log_sem);
|
||
if((self->count<MAX_LOG||self->log==NULL)&&self->stop !=1){
|
||
sem_post(&self->log_sem);
|
||
continue;
|
||
}
|
||
sem_post(&self->log_sem);
|
||
cleanup(self);
|
||
if(self->stop == 1){
|
||
return NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
int init_loger(log_manager *self)
|
||
{
|
||
if(self == NULL)
|
||
{
|
||
perror("NULL\n");
|
||
return -1;
|
||
}
|
||
if(sem_init(&self->log_sem, 0,1)==-1)
|
||
return -1;
|
||
if(pthread_mutex_init(&self->mtx,NULL)==-1)
|
||
{
|
||
if(sem_destroy(&self->log_sem)==-1)
|
||
{
|
||
perror("log:");
|
||
}
|
||
return -1;
|
||
}
|
||
if(pthread_cond_init(&self->cond,NULL)==-1)
|
||
{
|
||
if(sem_destroy(&self->log_sem)==-1)
|
||
{
|
||
perror("log:");
|
||
}
|
||
if(pthread_mutex_destroy(&self->mtx)==-1)
|
||
{
|
||
perror("log:");
|
||
}
|
||
return -1;
|
||
}
|
||
self->in_log = in_log;
|
||
self->out_log = out_log;
|
||
self->clear_log = clear_log;
|
||
self->log = NULL;
|
||
self->stop = 0;
|
||
self->cleanup = cleanup;
|
||
self->count = 0;
|
||
return 0;
|
||
} |