248 lines
6.5 KiB
C
Executable File
248 lines
6.5 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>
|
||
|
||
|
||
logs* getbody(void **log_p)
|
||
{
|
||
return (logs*)*log_p;
|
||
}
|
||
int write_into_block(char *writein,char *org,size_t* length,size_t 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+1;
|
||
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)
|
||
{
|
||
int eno = write(fd,writein,strlen(writein));
|
||
if(eno <strlen(writein))
|
||
perror("log");
|
||
close(fd);
|
||
}
|
||
else if(fd == -1)
|
||
perror("log:");//仅警告
|
||
strncpy(writein,&org[0],n);//剩余部分拷贝
|
||
*length = n;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int in_log(log_manager *self,const char *logbody,const char *info)
|
||
{
|
||
if(self == NULL)
|
||
return -1;
|
||
void **log_p = self->mempool->GetBlock(self->mempool,LOGMOD);
|
||
if(log_p == NULL)
|
||
{
|
||
perror("Mem_runout");
|
||
return -1;
|
||
}
|
||
logs *log = getbody(log_p);
|
||
snprintf(log->info,INFO_LENGTH,"%s",info);
|
||
snprintf(log->log,MAX_LOG_LENGTH,"%s",logbody);
|
||
log->log[MAX_LOG_LENGTH-1] = '\0';
|
||
log->next = NULL;
|
||
sem_wait(&self->log_sem);//加锁
|
||
if(self->log == NULL){
|
||
self->log = log_p;
|
||
self->rear = getbody(log_p);
|
||
atomic_fetch_add(&self->count,1);
|
||
sem_post(&self->log_sem);
|
||
return self->count;
|
||
}
|
||
if(self->count == 1){
|
||
logs *p = getbody(self->log);
|
||
p->next = log_p;
|
||
}
|
||
self->count++;
|
||
log->next = NULL;
|
||
self->rear->next = log_p;
|
||
self->rear = log;
|
||
sem_post(&self->log_sem);
|
||
return self->count;
|
||
}
|
||
|
||
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 += LOG_SLEEP_LENGTH;
|
||
/* 纳秒部分无需处理,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;
|
||
void **tobeclean_p;
|
||
sem_wait(&self->log_sem);//获取信号量
|
||
void **loc_p = self->log;
|
||
|
||
self->log = NULL;
|
||
atomic_store(&self->count,0);//摘取log链
|
||
sem_post(&self->log_sem);
|
||
//释放信号量
|
||
loc = getbody(loc_p);
|
||
|
||
char logbuf[MAX_LOG_LENGTH];
|
||
|
||
size_t buf_length = 0;
|
||
int fd;
|
||
while(loc->next !=NULL)
|
||
{
|
||
tobeclean_p = loc_p;
|
||
tobeclean = getbody(tobeclean_p);
|
||
loc_p = loc->next;
|
||
loc = getbody(loc_p);
|
||
|
||
int eno = write_into_block(logbuf,tobeclean->info,&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
if(eno == -1)
|
||
perror("log");
|
||
eno = write_into_block(logbuf,":",&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
eno = write_into_block(logbuf,tobeclean->log,&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
if(eno == -1)
|
||
perror("log");//非业务逻辑只警告
|
||
|
||
self->mempool->FreeBlock(self->mempool,tobeclean_p);
|
||
}
|
||
write_into_block(logbuf,loc->info,&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
write_into_block(logbuf,":",&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
write_into_block(logbuf,loc->log,&buf_length,MAX_LOG_LENGTH,"log.txt");
|
||
|
||
self->mempool->FreeBlock(self,loc_p);
|
||
|
||
fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND, 0644);
|
||
if(fd == -1){
|
||
perror("log:");
|
||
}
|
||
int error_buf = write(fd,logbuf,strlen(logbuf));
|
||
if(error_buf==-1){
|
||
return -1;
|
||
}
|
||
else if(error_buf<strlen(logbuf)){
|
||
perror("file");
|
||
write(fd,"unknown error case log write cut down\n",38);
|
||
}
|
||
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");
|
||
self->in_log(self,"stopping loger\n","SYS:");
|
||
printf("SYS:done\n");
|
||
self->in_log(self,"done","SYS:");
|
||
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,mem_ctl *mempool)
|
||
{
|
||
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->clear_log = clear_log;
|
||
self->log = NULL;
|
||
self->stop = 0;
|
||
self->cleanup = cleanup;
|
||
atomic_init(&self->count,0);
|
||
self->mempool = mempool;
|
||
return 0;
|
||
} |