root/eaccelerator/tags/0.9.2a/eaccelerator.c

Revision 44, 228.3 kB (checked in by segv74, 4 years ago)

1. pretty disassembler's output
2. change FE_FETCH's opcode type from EXT_FETCH to EXT_FE (FE = foreach)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
</
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | eAccelerator project                                                 |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2004 eAccelerator                                      |
6    | http://eaccelerator.sourceforge.net                                  |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    | Author(s): Dmitry Stogov <dstogov@users.sourceforge.net>             |
26    |            Seung Woo <segv@sayclub.com>                              |
27    |            Everaldo Canuto <everaldo_canuto@yahoo.com.br>            |
28    +----------------------------------------------------------------------+
29    $Id$
30 */
31
32 #include "eaccelerator.h"
33 #include "eaccelerator_version.h"
34
35 #ifdef HAVE_EACCELERATOR
36
37 #include "opcodes.h"
38
39 #include "zend.h"
40 #include "zend_API.h"
41 #include "zend_extensions.h"
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #ifdef ZEND_WIN32
46 #  include "win32/time.h"
47 #  include <time.h>
48 #  include <sys/utime.h>
49 #else
50 #  include <sys/file.h>
51 #  include <sys/time.h>
52 #  include <utime.h>
53 #endif
54 #include <fcntl.h>
55
56 #ifndef O_BINARY
57 #  define O_BINARY 0
58 #endif
59
60 /*???
61 #ifdef HAVE_SCHED_H
62 #  include <sched.h>
63 #endif
64 */
65
66 #ifdef ZEND_WIN32
67 #  include <process.h>
68 #  ifndef S_ISREG
69 #    define S_ISREG(mode) (((mode)&S_IFMT) & S_IFREG)
70 #  endif
71 #  ifndef S_IRUSR
72 #    define S_IRUSR S_IREAD
73 #  endif
74 #  ifndef S_IWUSR
75 #    define S_IWUSR S_IWRITE
76 #  endif
77 #else
78 #  include <dirent.h>
79 #endif
80
81 #include "php.h"
82 #include "php_ini.h"
83 #include "php_logos.h"
84 #include "main/fopen_wrappers.h"
85 #include "ext/standard/info.h"
86 #include "ext/standard/php_incomplete_class.h"
87 #include "ext/standard/md5.h"
88
89 #ifndef INCOMPLETE_CLASS
90 #  define INCOMPLETE_CLASS "__PHP_Incomplete_Class"
91 #endif
92 #ifndef MAGIC_MEMBER
93 #  define MAGIC_MEMBER "__PHP_Incomplete_Class_Name"
94 #endif
95
96 #include "SAPI.h"
97
98 #undef HAVE_PHP_SESSIONS_SUPPORT
99 #ifdef HAVE_EXT_SESSION_PHP_SESSION_H
100 #  include "ext/session/php_session.h"
101 #   ifdef PHP_SESSION_API
102 #     if PHP_SESSION_API >= 20020306
103 #       define HAVE_PHP_SESSIONS_SUPPORT
104 static int eaccelerator_sessions_registered = 0;
105 #       ifdef PS_CREATE_SID_ARGS
106 #         include "ext/standard/php_lcg.h"
107 #       endif
108 #     endif
109 #   endif
110 #endif
111
112 #define MAX_DUP_STR_LEN 256
113
114 #define offsetof(str,fld) ((size_t)&(((str*)NULL)->fld))
115
116 #ifdef EACCELERATOR_WITHOUT_FILE_LOCKING
117 #  ifndef LOCK_SH
118 #    define LOCK_SH 1
119 #    define LOCK_EX 2
120 #    define LOCK_UN 8
121 #  endif
122 #  define EACCELERATOR_FLOCK(FILE,OP)
123 #else
124 #  ifndef ZEND_WIN32
125 #    ifdef HAVE_FLOCK
126 #      define EACCELERATOR_FLOCK(FILE,OP) flock((FILE),(OP))
127 #    else
128 #      ifndef LOCK_SH
129 #        define LOCK_SH 1
130 #        define LOCK_EX 2
131 #        define LOCK_UN 8
132 #      endif
133 #      define EACCELERATOR_FLOCK(FILE,OP)
134 #    endif
135 #  else
136 #    define LOCK_SH 0
137 #    define LOCK_EX 1
138 #    define LOCK_UN 2
139 #    define EACCELERATOR_FLOCK(FILE,OP) {OVERLAPPED offset = {0,0,0,0,NULL};\
140                                    if ((OP) == LOCK_EX) {\
141                                      LockFileEx((HANDLE)_get_osfhandle(FILE), \
142                                        LOCKFILE_EXCLUSIVE_LOCK, 0,\
143                                        1, 0, &offset);\
144                                    } else if ((OP) == LOCK_SH) {\
145                                      LockFileEx((HANDLE)_get_osfhandle(FILE), \
146                                        0, 0,\
147                                        1, 0, &offset);\
148                                    } else if ((OP) == LOCK_UN) {\
149                                      UnlockFileEx((HANDLE)_get_osfhandle(FILE), \
150                                        0,\
151                                        1, 0, &offset);\
152                                    }}
153 #  endif
154 #endif
155
156
157 typedef struct _eaccelerator_op_array {
158   zend_uchar type;
159 #ifdef ZEND_ENGINE_2
160   zend_bool uses_this;
161 #else
162   zend_bool uses_globals;
163 #endif
164   zend_bool return_reference;
165 #ifdef ZEND_ENGINE_2
166   zend_uint num_args;
167   zend_uint required_num_args;
168   zend_arg_info *arg_info;
169   zend_bool pass_rest_by_reference;
170 #else
171   zend_uchar *arg_types;
172 #endif
173   char *function_name;
174   char *function_name_lc;
175 #ifdef ZEND_ENGINE_2
176   char* scope_name;
177   int   scope_name_len;
178   zend_uint fn_flags;
179 #endif
180   zend_op *opcodes;
181   zend_uint last;
182   zend_uint T;
183   zend_brk_cont_element *brk_cont_array;
184   zend_uint last_brk_cont;
185 #ifdef ZEND_ENGINE_2
186         /* HOESH: try & catch support */
187         zend_try_catch_element* try_catch_array;
188         int last_try_catch;
189 #endif
190   HashTable *static_variables;
191   char *filename;
192 #ifdef ZEND_ENGINE_2
193   zend_uint line_start;
194   zend_uint line_end;
195   char *doc_comment;
196   zend_uint doc_comment_len;
197 #endif
198 } eaccelerator_op_array;
199
200 typedef struct _eaccelerator_class_entry {
201   char type;
202   char *name;
203   char *name_lc;
204   uint name_length;
205   char *parent;
206   HashTable function_table;
207   HashTable default_properties;
208 #ifdef ZEND_ENGINE_2
209   zend_uint ce_flags;
210   HashTable *static_members;
211   HashTable properties_info;
212   HashTable constants_table;
213   zend_uint num_interfaces;
214   char **interfaces;
215   zend_class_iterator_funcs iterator_funcs;
216
217   zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
218   zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object TSRMLS_DC);
219   int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
220    
221   char *filename;
222   zend_uint line_start;
223   zend_uint line_end;
224   char *doc_comment;
225   zend_uint doc_comment_len;
226 #endif
227 } eaccelerator_class_entry;
228
229 /*
230  * To cache functions and classes.
231  */
232 typedef struct _mm_fc_entry {
233   void   *fc;
234   struct _mm_fc_entry *next;
235   int    htablen;
236   char   htabkey[1];         /* must be last element */
237 } mm_fc_entry;
238
239 /*
240  * A mm_cache_entry is a bucket for one PHP script file.
241  * Nested  functions and classes which defined in the file goes
242  * into the list of mm_fc_entry.
243  */
244 typedef struct _mm_cache_entry {
245   struct _mm_cache_entry *next;
246 #ifdef EACCELERATOR_USE_INODE
247   dev_t                  st_dev;         /* file's device                     */
248   ino_t                  st_ino;         /* file's inode                      */
249 #else
250   unsigned int           hv;             /* hash value                        */
251 #endif
252   off_t                  filesize;       /* file size */
253   time_t                 mtime;          /* file last modification time       */
254   time_t                 ttl;            /* expiration time                   */
255   int                    size;           /* entry size (bytes)                */
256   int                    nhits;          /* hits count                        */
257   int                    nreloads;       /* count of reloads                  */
258   int                    use_cnt;        /* how many processes uses the entry */
259   eaccelerator_op_array       *op_array;      /* script's global scope code        */
260   mm_fc_entry            *f_head;        /* list of nested functions          */
261   mm_fc_entry            *c_head;        /* list of nested classes            */
262   zend_bool              removed;        /* the entry is scheduled to remove  */
263   char                   realfilename[1];/* real file name (must be last el.) */
264 } mm_cache_entry;
265
266 /*
267  * bucket for user's cache
268  */
269 typedef struct _mm_user_cache_entry {
270   struct _mm_user_cache_entry *next;
271   unsigned int           hv;            /* hash value                  */
272   long                   ttl;           /* expiration time             */
273   int                    size;
274   zval                   value;         /* value                       */
275   char                   key[1];        /* key value (must be last el) */
276 } mm_user_cache_entry;
277
278 /*
279  * Linked list of mm_cache_entry which are used by process/thread
280  */
281 typedef struct _mm_used_entry {
282   struct _mm_used_entry *next;
283   mm_cache_entry        *entry;
284 } mm_used_entry;
285
286 /*
287  * Linked list of locks
288  */
289 typedef struct _mm_lock_entry {
290   struct _mm_lock_entry *next;
291   pid_t  pid;
292 #ifdef ZTS
293   THREAD_T thread;
294 #endif
295   char                  key[1];
296 } mm_lock_entry;
297
298 typedef struct _mm_file_header {
299   char   magic[8];        /* "EACCELERATOR" */
300   int    eaccelerator_version;
301   int    zend_version;
302   int    php_version;
303   int    size;
304   time_t mtime;
305   unsigned int crc32;
306 } mm_file_header;
307
308 #ifdef ZTS
309 #  define ZTS_LOCK()    tsrm_mutex_lock(mm_mutex)
310 #  define ZTS_UNLOCK()  tsrm_mutex_unlock(mm_mutex)
311 #else
312 #  define ZTS_LOCK()
313 #  define ZTS_UNLOCK()
314 #endif
315
316 #include "mm.h"
317
318 #if defined(EACCELERATOR_PROTECT_SHM)
319 #  define EACCELERATOR_PROTECT()    do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ);} while(0)
320 #  define EACCELERATOR_UNPROTECT()  do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ|MM_PROT_WRITE);} while(0)
321 #else
322 #  define EACCELERATOR_PROTECT()
323 #  define EACCELERATOR_UNPROTECT()
324 #endif
325
326 #define EACCELERATOR_LOCK_RW()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RW);} while(0)
327 #define EACCELERATOR_LOCK_RD()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RD);} while(0)
328 #define EACCELERATOR_UNLOCK()     do {mm_unlock(eaccelerator_mm_instance->mm); ZTS_UNLOCK();} while(0)
329 #define EACCELERATOR_UNLOCK_RW()  EACCELERATOR_UNLOCK()
330 #define EACCELERATOR_UNLOCK_RD()  EACCELERATOR_UNLOCK()
331
332 #define EACCELERATOR_BLOCK_INTERRUPTIONS()   HANDLE_BLOCK_INTERRUPTIONS()
333 #define EACCELERATOR_UNBLOCK_INTERRUPTIONS() HANDLE_UNBLOCK_INTERRUPTIONS()
334
335 #define MM_HASH_SIZE      256
336 #define MM_USER_HASH_SIZE 256
337 #define MM_HASH_MAX       (MM_HASH_SIZE-1)
338 #define MM_USER_HASH_MAX  (MM_USER_HASH_SIZE-1)
339
340 #define eaccelerator_malloc(size)        mm_malloc(eaccelerator_mm_instance->mm, size)
341 #define eaccelerator_free(x)             mm_free(eaccelerator_mm_instance->mm, x)
342 #define eaccelerator_malloc_nolock(size) mm_malloc_nolock(eaccelerator_mm_instance->mm, size)
343 #define eaccelerator_free_nolock(x)      mm_free_nolock(eaccelerator_mm_instance->mm, x)
344
345 typedef struct {
346   MM             *mm;
347   pid_t          owner;
348   size_t         total;
349   unsigned int   hash_cnt;
350   unsigned int   user_hash_cnt;
351   zend_bool      enabled;
352   zend_bool      optimizer_enabled;
353   unsigned int   rem_cnt;
354   time_t         last_prune;
355   mm_cache_entry *removed;
356   mm_lock_entry  *locks;
357
358   mm_cache_entry      *hash[MM_HASH_SIZE];
359   mm_user_cache_entry *user_hash[MM_USER_HASH_SIZE];
360 } eaccelerator_mm;
361
362 /*
363  * Globals (different for each process/thread)
364  */
365 ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
366
367 /*
368  * Globals (common for each process/thread)
369  */
370 static long eaccelerator_shm_size = 0;
371 static long eaccelerator_shm_max = 0;
372 static long eaccelerator_shm_ttl = 0;
373 static long eaccelerator_shm_prune_period = 0;
374 static long eaccelerator_debug = 0;
375 static zend_bool eaccelerator_check_mtime = 1;
376 static zend_bool eaccelerator_scripts_shm_only = 0;
377 static eaccelerator_cache_place eaccelerator_keys_cache_place     = eaccelerator_shm_and_disk;
378 static eaccelerator_cache_place eaccelerator_sessions_cache_place = eaccelerator_shm_and_disk;
379        eaccelerator_cache_place eaccelerator_content_cache_place  = eaccelerator_shm_and_disk;
380
381 static eaccelerator_mm* eaccelerator_mm_instance = NULL;
382 static int eaccelerator_is_zend_extension = 0;
383 static int eaccelerator_is_extension      = 0;
384 static zend_extension* ZendOptimizer = NULL;
385 #ifdef ZTS
386 static MUTEX_T mm_mutex;
387 #endif
388
389 static HashTable eaccelerator_global_function_table;
390 static HashTable eaccelerator_global_class_table;
391
392 static int binary_eaccelerator_version;
393 static int binary_php_version;
394 static int binary_zend_version;
395
396 /* saved original functions */
397 static zend_op_array *(*mm_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
398
399 #if defined(PROFILE_OPCODES) || defined(WITH_EACCELERATOR_EXECUTOR)
400 static void (*mm_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
401 #endif
402
403 /* external declarations */
404 PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
405 PHPAPI char *php_get_uname();
406
407 ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
408
409
410 #if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
411 #include <ctype.h>
412 #include <stdio.h>
413 static FILE *F_fp;
414
415 static void binary_print(char *p, int len) {
416   while (len--) {
417     fputc(*p++, F_fp);
418   }
419   fputc('\n', F_fp);
420 }
421
422 static void log_hashkeys(char *p, HashTable *ht)
423 {
424   Bucket *b;
425   int i = 0;
426
427   b = ht->pListHead;
428
429   fputs(p, F_fp);
430   while (b) {
431     fprintf(F_fp, "[%d] ", i);
432     binary_print(b->arKey, b->nKeyLength);
433
434     b = b->pListNext;
435     i++;
436   }
437 }
438
439 static void pad(TSRMLS_D) {
440   int i = MMCG(xpad);
441   while (i-- > 0) {
442     fputc('\t', F_fp);
443   }
444 }
445
446 static void start_time(struct timeval *tvstart) {
447   gettimeofday(tvstart, NULL);
448 }
449
450 static long elapsed_time(struct timeval *tvstart) {
451   struct timeval tvend;
452   int sec, usec;
453   gettimeofday(&tvend, NULL);
454   sec = tvend.tv_sec - tvstart->tv_sec;
455   usec = tvend.tv_usec - tvstart->tv_usec;
456   return sec * 1000000 + usec;
457 }
458 #endif  /* #if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES) */
459
460 static inline unsigned int hash_mm(const char *data, int len) {
461   unsigned int h;
462   const char *e = data + len;
463   for (h = 2166136261U; data < e; ) {
464     h *= 16777619;
465     h ^= *data++;
466   }
467   return h;
468 }
469
470 static mm_cache_entry* hash_find_mm(const char  *key,
471                                     struct stat *buf,
472                                     int         *nreloads,
473                                     time_t      ttl) {
474   unsigned int hv, slot;
475   mm_cache_entry *p, *q;
476
477 #ifdef EACCELERATOR_USE_INODE
478   hv = buf->st_dev + buf->st_ino;
479 #else
480   hv = hash_mm(key, strlen(key));
481 #endif
482   slot = hv & MM_HASH_MAX;
483
484   EACCELERATOR_LOCK_RW();
485   q = NULL;
486   p = eaccelerator_mm_instance->hash[slot];
487   while (p != NULL) {
488 #ifdef EACCELERATOR_USE_INODE
489     if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
490       struct stat buf2;
491       if ((eaccelerator_check_mtime &&
492           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
493           (strcmp(p->realfilename, key) != 0 &&
494            (stat(p->realfilename,&buf2) != 0 ||
495            buf2.st_dev != buf->st_dev ||
496            buf2.st_ino != buf->st_ino))) {
497 #else
498     if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
499       if (eaccelerator_check_mtime &&
500           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
501 #endif
502         /* key is invalid. Remove it. */
503         *nreloads = p->nreloads+1;
504         if (q == NULL) {
505           eaccelerator_mm_instance->hash[slot] = p->next;
506         } else {
507           q->next = p->next;
508         }
509         eaccelerator_mm_instance->hash_cnt--;
510         if (p->use_cnt > 0) {
511           /* key is used by other process/thred. Shedule it to remove */
512           p->removed = 1;
513           p->next = eaccelerator_mm_instance->removed;
514           eaccelerator_mm_instance->removed = p;
515           eaccelerator_mm_instance->rem_cnt++;
516           EACCELERATOR_UNLOCK_RW();
517           return NULL;
518         } else {
519           /* key is unused. Remove it. */
520           eaccelerator_free_nolock(p);
521           EACCELERATOR_UNLOCK_RW();
522           return NULL;
523         }
524       } else {
525         /* key is valid */
526         p->nhits++;
527         p->use_cnt++;
528         p->ttl = ttl;
529         EACCELERATOR_UNLOCK_RW();
530         return p;
531       }
532     }
533     q = p;
534     p = p->next;
535   }
536   EACCELERATOR_UNLOCK_RW();
537   return NULL;
538 }
539
540 static void hash_add_mm(mm_cache_entry *x) {
541   mm_cache_entry *p,*q;
542   unsigned int slot;
543 #ifdef EACCELERATOR_USE_INODE
544   slot = (x->st_dev + x->st_ino) & MM_HASH_MAX;
545 #else
546   x->hv = hash_mm(x->realfilename, strlen(x->realfilename));
547   slot = x->hv & MM_HASH_MAX;
548 #endif
549
550   EACCELERATOR_LOCK_RW();
551   x->next = eaccelerator_mm_instance->hash[slot];
552   eaccelerator_mm_instance->hash[slot] = x;
553   eaccelerator_mm_instance->hash_cnt++;
554   q = x;
555   p = x->next;
556   while (p != NULL) {
557 #ifdef EACCELERATOR_USE_INODE
558     if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
559 #else
560     if ((p->hv == x->hv) &&
561         (strcmp(p->realfilename, x->realfilename) == 0)) {
562 #endif
563       q->next = p->next;
564       eaccelerator_mm_instance->hash_cnt--;
565       eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
566       if (p->use_cnt > 0) {
567         /* key is used by other process/thred. Shedule it to remove */
568         p->removed = 1;
569         p->next = eaccelerator_mm_instance->removed;
570         eaccelerator_mm_instance->removed = p;
571         eaccelerator_mm_instance->rem_cnt++;
572         EACCELERATOR_UNLOCK_RW();
573         return;
574       } else {
575         /* key is unused. Remove it. */
576         eaccelerator_free_nolock(p);
577         EACCELERATOR_UNLOCK_RW();
578         return;
579       }
580     }
581     q = p;
582     p = p->next;
583   }
584   EACCELERATOR_UNLOCK_RW();
585 }
586
587 static int init_mm(TSRMLS_D) {
588   pid_t  owner = getpid();
589   MM     *mm;
590   size_t total;
591   char   mm_path[MAXPATHLEN];
592
593 /*  if (getppid() != 1) return SUCCESS; */ /*???*/
594 #ifdef ZEND_WIN32
595     snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
596 #else
597     snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, getpid());
598 #endif
599 /*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
600   if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(eaccelerator_shm_size*1024*1024, mm_path)) != NULL) {
601 #ifdef ZTS
602     mm_mutex = tsrm_mutex_alloc();
603 #endif
604     return SUCCESS;
605   }
606   mm = mm_create(eaccelerator_shm_size*1024*1024, mm_path);
607   if (!mm) {
608     return FAILURE;
609   }
610 #ifdef DEBUG
611 #ifdef ZEND_WIN32
612   fprintf(F_fp, "init_mm [%d]\n", getpid());
613 #else
614   fprintf(F_fp, "init_mm [%d,%d]\n", getpid(), getppid());
615 #endif
616   fflush(F_fp);
617 #endif
618 #ifdef ZTS
619   mm_mutex = tsrm_mutex_alloc();
620 #endif
621   total = mm_available(mm);
622   eaccelerator_mm_instance = mm_malloc(mm, sizeof(*eaccelerator_mm_instance));
623   if (!eaccelerator_mm_instance) {
624     return FAILURE;
625   }
626   mm_set_attach(mm, eaccelerator_mm_instance);
627   memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
628   eaccelerator_mm_instance->owner = owner;
629   eaccelerator_mm_instance->mm    = mm;
630   eaccelerator_mm_instance->total = total;
631   eaccelerator_mm_instance->hash_cnt = 0;
632   eaccelerator_mm_instance->rem_cnt  = 0;
633   eaccelerator_mm_instance->enabled = 1;
634   eaccelerator_mm_instance->optimizer_enabled = 1;
635   eaccelerator_mm_instance->removed = NULL;
636   eaccelerator_mm_instance->locks = NULL;
637   eaccelerator_mm_instance->user_hash_cnt = 0;
638   eaccelerator_mm_instance->last_prune = time(0);
639   EACCELERATOR_PROTECT();
640   return SUCCESS;
641 }
642
643 static void shutdown_mm(TSRMLS_D) {
644   if (eaccelerator_mm_instance) {
645 #ifdef ZEND_WIN32
646     if (eaccelerator_mm_instance->owner == getpid()) {
647 #else
648     if (getpgrp() == getpid()) {
649 #endif
650       MM *mm = eaccelerator_mm_instance->mm;
651 #ifdef DEBUG
652 #ifdef ZEND_WIN32
653       fprintf(F_fp, "shutdown_mm [%d]\n", getpid());
654 #else
655       fprintf(F_fp, "shutdown_mm [%d,%d]\n", getpid(), getppid());
656 #endif
657       fflush(F_fp);
658 #endif
659 #ifdef ZTS
660       tsrm_mutex_free(mm_mutex);
661 #endif
662       if (mm) {
663         mm_destroy(mm);
664       }
665       eaccelerator_mm_instance = NULL;
666     }
667   }
668 }
669
670 static void debug_printf(char *format, ...) {
671   char output_buf[512];
672   va_list args;
673
674   va_start(args, format);
675   vsnprintf(output_buf, sizeof(output_buf), format, args);
676   va_end(args);
677
678 #ifdef ZEND_WIN32
679   OutputDebugString(output_buf);
680 /*  zend_printf("EACCELERATOR: %s<br>\n",output_buf);*/
681 #else
682   fputs(output_buf, stderr);
683 #endif
684 }
685
686 /******************************************************************************/
687
688 #define FIXUP(x) if((x)!=NULL) {(x) = (void*)(((char*)(x)) + ((long)(MMCG(mem))));}
689
690 static void fixup_zval(zval* z TSRMLS_DC);
691
692 typedef void (*fixup_bucket_t)(void* TSRMLS_DC);
693
694 #define fixup_zval_hash(from) \
695   fixup_hash(from, (fixup_bucket_t)fixup_zval TSRMLS_CC)
696
697 #ifdef ZEND_ENGINE_2
698 static void fixup_property_info(zend_property_info* from TSRMLS_DC) {
699   FIXUP(from->name);
700 }
701 #endif
702
703 static void fixup_hash(HashTable* source, fixup_bucket_t fixup_bucket TSRMLS_DC) {
704   unsigned int i;
705   Bucket *p;
706
707   if (source->nNumOfElements > 0) {
708     if (!MMCG(compress)) {
709       if (source->arBuckets != NULL) {
710         FIXUP(source->arBuckets);
711         for (i = 0; i < source->nTableSize; i++) {
712           FIXUP(source->arBuckets[i]);
713         }
714       }
715     }
716     FIXUP(source->pListHead);
717     FIXUP(source->pListTail);
718
719     p = source->pListHead;
720     while (p) {
721       FIXUP(p->pNext);
722       FIXUP(p->pLast);
723       FIXUP(p->pData);
724       FIXUP(p->pDataPtr);
725       FIXUP(p->pListLast);
726       FIXUP(p->pListNext);
727       if (p->pDataPtr) {
728         fixup_bucket(p->pDataPtr TSRMLS_CC);
729         p->pData = &p->pDataPtr;
730       } else {
731         fixup_bucket(p->pData TSRMLS_CC);
732       }
733       p = p->pListNext;
734     }
735     source->pInternalPointer = source->pListHead;
736   }
737 }
738
739 static void fixup_zval(zval* zv TSRMLS_DC) {
740   switch (zv->type) {
741     case IS_CONSTANT:
742     case IS_STRING:
743       if (zv->value.str.val == NULL ||
744          zv->value.str.len == 0) {
745         zv->value.str.val = empty_string;
746         zv->value.str.len = 0;
747       } else {
748         FIXUP(zv->value.str.val);
749       }
750       break;
751     case IS_ARRAY:
752     case IS_CONSTANT_ARRAY:
753       if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
754       } else {
755         FIXUP(zv->value.ht);
756         fixup_zval_hash(zv->value.ht);
757       }
758       break;
759     case IS_OBJECT:
760       if (!MMCG(compress)) {
761         return;
762       }
763 #ifndef ZEND_ENGINE_2
764       FIXUP(zv->value.obj.ce);
765       if (zv->value.obj.properties != NULL) {
766         FIXUP(zv->value.obj.properties);
767         fixup_zval_hash(zv->value.obj.properties);
768       }
769 #endif
770     default:
771       break;
772   }
773 }
774
775 static void fixup_op_array(eaccelerator_op_array* from TSRMLS_DC) {
776   zend_op *opline;
777   zend_op *end;
778
779 #ifdef ZEND_ENGINE_2
780   if (from->num_args > 0) {
781     zend_uint i;
782     FIXUP(from->arg_info);
783     for (i = 0; i < from->num_args; i++) {
784       FIXUP(from->arg_info[i].name);
785       FIXUP(from->arg_info[i].class_name);
786     }
787   }
788 #else
789   FIXUP(from->arg_types);
790 #endif
791   FIXUP(from->function_name);
792 #ifdef ZEND_ENGINE_2
793   FIXUP(from->scope_name);
794 #endif
795   if (from->type == ZEND_INTERNAL_FUNCTION) {
796     return;
797   }
798
799   if (from->opcodes != NULL) {
800     FIXUP(from->opcodes);
801
802     opline = from->opcodes;
803     end = opline + from->last;
804     MMCG(compress) = 0;
805     for (;opline < end; opline++) {
806 /*
807       if (opline->result.op_type == IS_CONST) fixup_zval(&opline->result.u.constant  TSRMLS_CC);
808 */
809       if (opline->op1.op_type    == IS_CONST) fixup_zval(&opline->op1.u.constant TSRMLS_CC);
810       if (opline->op2.op_type    == IS_CONST) fixup_zval(&opline->op2.u.constant TSRMLS_CC);
811 #ifdef ZEND_ENGINE_2
812       switch (opline->opcode) {
813         case ZEND_JMP:
814           FIXUP(opline->op1.u.jmp_addr);
815           break;
816         case ZEND_JMPZ:
817         case ZEND_JMPNZ:
818         case ZEND_JMPZ_EX:
819         case ZEND_JMPNZ_EX:
820           FIXUP(opline->op2.u.jmp_addr);
821           break;
822       }
823       opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
824 #endif
825     }
826     MMCG(compress) = 1;
827   }
828   FIXUP(from->brk_cont_array);
829 #ifdef ZEND_ENGINE_2
830         /* HOESH: try & catch support */
831         FIXUP(from->try_catch_array);
832 #endif
833   if (from->static_variables != NULL) {
834     FIXUP(from->static_variables);
835     fixup_zval_hash(from->static_variables);
836   }
837   FIXUP(from->filename);
838 #ifdef ZEND_ENGINE_2
839   FIXUP(from->doc_comment);
840 #endif
841 }
842
843 static void fixup_class_entry(eaccelerator_class_entry* from TSRMLS_DC) {
844   FIXUP(from->name);
845   FIXUP(from->parent);
846 #ifdef ZEND_ENGINE_2
847   FIXUP(from->filename);
848   FIXUP(from->doc_comment);
849   fixup_zval_hash(&from->constants_table);
850   fixup_zval_hash(&from->default_properties);
851   fixup_hash(&from->properties_info, (fixup_bucket_t)fixup_property_info TSRMLS_CC);
852   if (from->static_members != NULL) {
853     FIXUP(from->static_members);
854     fixup_zval_hash(from->static_members);
855   }
856 #else
857   fixup_zval_hash(&from->default_properties);
858 #endif
859   fixup_hash(&from->function_table, (fixup_bucket_t)fixup_op_array TSRMLS_CC);
860 }
861
862 static void eaccelerator_fixup(mm_cache_entry *p TSRMLS_DC) {
863   mm_fc_entry* q;
864
865   MMCG(mem) = (char*)((long)p - (long)p->next);
866   MMCG(compress) = 1;
867   p->next        = NULL;
868   FIXUP(p->op_array);
869   FIXUP(p->f_head);
870   FIXUP(p->c_head);
871   fixup_op_array(p->op_array TSRMLS_CC);
872   q = p->f_head;
873   while (q != NULL) {
874     FIXUP(q->fc);
875     fixup_op_array((eaccelerator_op_array*)q->fc TSRMLS_CC);
876     FIXUP(q->next);
877     q = q->next;
878   }
879   q = p->c_head;
880   while (q != NULL) {
881     FIXUP(q->fc);
882     fixup_class_entry((eaccelerator_class_entry*)q->fc TSRMLS_CC);
883     FIXUP(q->next);
884     q = q->next;
885   }
886 }
887
888 /******************************************************************************/
889
890 static int encode_version(const char *s) {
891   unsigned int v1 = 0;
892   unsigned int v2 = 0;
893   unsigned int v3 = 0;
894   unsigned int c;
895   char m = '.';
896   sscanf(s, "%u.%u%c%u",&v1,&v2,&m,&v3);
897   switch (m) {
898     case  'a': c = 0; break;
899     case  'b': c = 1; break;
900     case  '.': c = 2; break;
901     case  's': c = 15; break;
902     default: c = 2;
903   }
904   return ((v1 & 0xf) << 20) |
905          ((v2 & 0xff) << 12) |
906          ((c & 0xf) << 8) |
907          (v3 & 0xff);
908 }
909
910 static void decode_version(char *version, int v) {
911   int t = (v & 0x000f00) >> 8;
912   char c;
913   switch (t) {
914     case  0: c = 'a'; break;
915     case  1: c = 'b'; break;
916     case  2: c = '.'; break;
917     case 15: c = 's'; break;
918     default: c = '.';
919   }
920   snprintf(version, 16, "%d.%d%c%d", (v & 0xf00000) >> 20,
921                                      (v & 0x0ff000) >> 12,
922                                      c,
923                                      (v & 0x0000ff));
924 }
925
926 #ifdef EACCELERATOR_USE_INODE
927 static int eaccelerator_inode_key(char* s, dev_t dev, ino_t ino TSRMLS_DC) {
928   int n;
929   strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
930   strlcat(s, "/eaccelerator-", MAXPATHLEN-1);
931   n = strlen(s);
932   while (dev > 0) {
933     if (n >= MAXPATHLEN) return 0;
934     s[n++] = (dev % 10) +'0';
935     dev /= 10;
936   }
937   if (n >= MAXPATHLEN) return 0;
938   s[n++] = '.';
939   while (ino > 0) {
940     if (n >= MAXPATHLEN) return 0;
941     s[n++] = (ino % 10) +'0';
942     ino /= 10;
943   }
944   if (n >= MAXPATHLEN) return 0;
945   s[n++] = '\000';
946   return 1;
947 }
948 #endif
949
950 static int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
951 #if defined(PHP_MAJOR_VERSION) && defined(PHP_MINOR_VERSION) && \
952     ((PHP_MAJOR_VERSION > 4) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION > 1))
953   char md5str[33];
954   PHP_MD5_CTX context;
955   unsigned char digest[16];
956
957   md5str[0] = '\0';
958   PHP_MD5Init(&context);
959   PHP_MD5Update(&context, key, strlen(key));
960   PHP_MD5Final(digest, &context);
961   make_digest(md5str, digest);
962   snprintf(s, MAXPATHLEN-1, "%s%s%s", MMCG(cache_dir), prefix, md5str);
963   return 1;
964 #else
965   zval retval;
966   zval md5;
967   zval param;
968   zval *params[1];
969
970   ZVAL_STRING(&md5, "md5", 0);
971   INIT_ZVAL(param);
972   params[0] = &param;
973   ZVAL_STRING(params[0], (char*)key, 0);
974   if (call_user_function(CG(function_table), (zval**)NULL, &md5, &retval, 1, params TSRMLS_CC) == SUCCESS &&
975       retval.type == IS_STRING &&
976       retval.value.str.len == 32) {
977     strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
978     strlcat(s, prefix, MAXPATHLEN);
979     strlcat(s, retval.value.str.val, MAXPATHLEN);
980     zval_dtor(&retval);
981     return 1;
982   }
983   s[0] ='\0';
984 #endif
985   return 0;
986 }
987
988 static void eaccelerator_prune(time_t t) {
989   unsigned int i;
990
991   EACCELERATOR_LOCK_RW();
992   eaccelerator_mm_instance->last_prune = t;
993   for (i = 0; i < MM_HASH_SIZE; i++) {
994     mm_cache_entry **p = &eaccelerator_mm_instance->hash[i];
995     while (*p != NULL) {
996       struct stat buf;
997       if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
998           stat((*p)->realfilename,&buf) != 0 ||
999 #ifdef EACCELERATOR_USE_INODE
1000           (*p)->st_dev != buf.st_dev ||
1001           (*p)->st_ino != buf.st_ino ||
1002 #endif
1003           (*p)->mtime != buf.st_mtime ||
1004           (*p)->filesize != buf.st_size) {
1005         mm_cache_entry *r = *p;
1006         *p = (*p)->next;
1007         eaccelerator_mm_instance->hash_cnt--;
1008         eaccelerator_free_nolock(r);
1009       } else {
1010         p = &(*p)->next;
1011       }
1012     }
1013   }
1014   EACCELERATOR_UNLOCK_RW();
1015 }
1016
1017 static void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
1018   void *p = NULL;
1019   time_t t;
1020
1021   if (eaccelerator_gc(TSRMLS_C) > 0) {
1022     p = eaccelerator_malloc(size);
1023     if (p != NULL) {
1024       return p;
1025     }
1026   }
1027   if (eaccelerator_shm_prune_period > 0) {
1028     t = time(0);
1029     if (t - eaccelerator_mm_instance->last_prune > eaccelerator_shm_prune_period) {
1030       eaccelerator_prune(t);
1031       p = eaccelerator_malloc(size);
1032     }
1033   }
1034   return p;
1035 }
1036
1037 #define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
1038
1039 static const unsigned int crc32tab[256] = {
1040   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
1041   0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
1042   0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1043   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
1044   0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1045   0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1046   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
1047   0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
1048   0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1049   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1050   0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
1051   0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1052   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
1053   0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
1054   0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1055   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
1056   0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
1057   0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1058   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
1059   0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1060   0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1061   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
1062   0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
1063   0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1064   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1065   0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
1066   0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1067   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
1068   0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
1069   0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1070   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
1071   0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
1072   0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1073   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
1074   0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1075   0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1076   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
1077   0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
1078   0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1079   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1080   0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
1081   0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1082   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
1083   0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
1084   0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1085   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
1086   0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
1087   0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1088   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
1089   0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1090   0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1091   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
1092   0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
1093   0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1094   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1095   0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1096   0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1097   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1098   0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
1099   0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1100   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
1101   0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1102   0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1103   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
1104 };
1105
1106 unsigned int eaccelerator_crc32(const char *p, size_t n) {
1107   unsigned int crc = ~0;
1108   for (; n--; ++p) {
1109     EACCELERATOR_CRC32(crc, *p);
1110   }
1111   return ~crc;
1112 }
1113
1114 static mm_cache_entry* hash_find_file(const char  *key,
1115                                       struct stat *buf TSRMLS_DC) {
1116   int f;
1117   char s[MAXPATHLEN];
1118   mm_file_header hdr;
1119   mm_cache_entry *p;
1120   int use_shm = 1;
1121
1122 #ifdef EACCELERATOR_USE_INODE
1123   struct stat buf2;
1124
1125   if (!eaccelerator_inode_key(s, buf->st_dev, buf->st_ino TSRMLS_CC)) {
1126     return NULL;
1127   }
1128 #else
1129   if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
1130     return NULL;
1131   }
1132 #endif
1133
1134   if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
1135     EACCELERATOR_FLOCK(f, LOCK_SH);
1136     if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
1137       EACCELERATOR_FLOCK(f, LOCK_UN);
1138       close(f);
1139       return NULL;
1140     }
1141     if (strncmp(hdr.magic,"EACCELERATOR",8) != 0 ||
1142         hdr.eaccelerator_version != binary_eaccelerator_version ||
1143         hdr.zend_version != binary_zend_version ||
1144         hdr.php_version != binary_php_version) {
1145       EACCELERATOR_FLOCK(f, LOCK_UN);
1146       close(f);
1147       unlink(s);
1148       return NULL;
1149     }
1150     p = eaccelerator_malloc(hdr.size);
1151     if (p == NULL) {
1152       p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
1153     }
1154     if (p == NULL) {
1155       p = emalloc(hdr.size);
1156       use_shm = 0;
1157     }
1158     if (p == NULL) {
1159       EACCELERATOR_FLOCK(f, LOCK_UN);
1160       close(f);
1161       return NULL;
1162     }
1163     if (read(f, p, hdr.size) != hdr.size ||
1164         p->size != hdr.size ||
1165         hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
1166       EACCELERATOR_FLOCK(f, LOCK_UN);
1167       close(f);
1168       unlink(s);
1169       if (use_shm) eaccelerator_free(p); else efree(p);
1170       return NULL;
1171     }
1172     EACCELERATOR_FLOCK(f, LOCK_UN);
1173     close(f);
1174 #ifdef EACCELERATOR_USE_INODE
1175     if (p->st_dev != buf->st_dev || p->st_ino != buf->st_ino) {
1176 #else
1177     if (strcmp(key,p->realfilename) != 0) {
1178 #endif
1179       if (use_shm) eaccelerator_free(p); else efree(p);
1180       return NULL;
1181     }
1182     if ((eaccelerator_check_mtime &&
1183         (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
1184 #ifdef EACCELERATOR_USE_INODE
1185         ||
1186         (strcmp(p->realfilename, key) != 0 &&
1187          (stat(p->realfilename,&buf2) != 0 ||
1188          buf2.st_dev != buf->st_dev ||
1189          buf2.st_ino != buf->st_ino))
1190 #endif
1191        ) {
1192       /* key is invalid. Remove it. */
1193       if (use_shm) eaccelerator_free(p); else efree(p);
1194       unlink(s);
1195       return NULL;
1196     }
1197     eaccelerator_fixup(p TSRMLS_CC);
1198     if (use_shm) {
1199       p->nhits    = 1;
1200       p->nreloads = 1;
1201       p->use_cnt  = 1;
1202       p->removed  = 0;
1203       if (eaccelerator_shm_ttl > 0) {
1204         p->ttl = time(0) + eaccelerator_shm_ttl;
1205       } else {
1206         p->ttl = 0;
1207       }
1208       hash_add_mm(p);
1209     } else {
1210       p->use_cnt  = 0;
1211       p->removed  = 1;
1212     }
1213     return p;
1214   }
1215   return NULL;
1216 }
1217