290 lines
7.4 KiB
C
Executable File
290 lines
7.4 KiB
C
Executable File
#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 write_into_block(char *writein,char *org,int *length,int maxlength,char *logname)
|
||
{
|
||
if(writein == NULL||org == NULL||length == NULL||logname == NULL)
|
||
return -1;
|
||
if(*length+strlen(org)<maxlength-1)
|
||
{
|
||
strcpy(&writein[*length],org);
|
||
*length +=strlen(org);//栈内存充足
|
||
}
|
||
else
|
||
{
|
||
int n = *length + strlen(org) - maxlength;
|
||
strncpy(&writein[*length],org,strlen(org)-n);//栈内存不足
|
||
writein[maxlength-1] = '\0';
|
||
int fd = open(logname,O_CREAT | O_WRONLY | O_APPEND, 0644);
|
||
if(fd != -1)
|
||
{
|
||
write(fd,writein,maxlength);
|
||
close(fd);
|
||
}
|
||
else if(fd == -1)
|
||
perror("log:");//仅警告
|
||
*length = n;
|
||
strcpy(writein,&org[*length]);//剩余部分拷贝
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
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 = 0,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;//降级策略,堆空间不足时,使用预分配栈空间
|
||
buf_length = 0;
|
||
}
|
||
if(logbuf != failback){
|
||
buf_lengthbk = buf_length;
|
||
buf_length = strlen(logbuf)+strlen(tobeclean->log);
|
||
strcpy(logbuf+buf_lengthbk,tobeclean->log);
|
||
}
|
||
else
|
||
{
|
||
write_into_block(logbuf,tobeclean->log,&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
}
|
||
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{
|
||
write_into_block(logbuf,loc->log,&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
}
|
||
|
||
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;
|
||
} |